Azure Mobile Service Filter - Removed? - c#

I've been reading about custom auth methods using Azure, and stumbled upon 12 Days of ZUMO. It's an excellent write up, but I can't seem to find anything related to IServiceFilter in the current .Net Client SDK for Azure.
I'm developing a Xamarin app in C#.
Has this functionality been removed or relocated? I have all Azure namespaces referenced and intellisense can't find IServiceFilter or anything else related to service filters.
Thanks for reading.

I currently develop an app for Android on Java (I don't think that library for C# is very different).
And I can access ServiceFilter. But I don't see IServiceFilter.
Namespace - com.microsoft.windowsazure.mobileservices.http.ServiceFilter
Library version - 2.0.2-beta2

In Xamarin you need to use a DelegateHandler instead. This is the standard .net way to filter http traffic.
public class MyLogFilter : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Do any pre-request requirements here
Log.Warning("http request", request.RequestUri.ToString() );
// Request happens here
var response = await base.SendAsync(request, cancellationToken);
// Do any post-request requirements here
Log.Warning("http response", response.StatusCode + " " + response.Content.ReadAsStringAsync().Result);
return response;
}
}
Once you've done that, you just chain the handler when initializing your MobileServiceClient, changing this:
Client = new MobileServiceClient (API_URL, new MyExistingHandler());
to:
Client = new MobileServiceClient (API_URL, new MyLogFilter(), new MyExistingHandler());

Related

Implement sending Server Sent Events in C# (no ASP.NET / MVC / ...)

For a project, I need to implement SSE (Server Sent Events) in a C# Application. Although this may sound easy, I've got no clue how to solve this.
As I'm new to C# (though, not new to programming in general) I took an excursion to Google and tried to look for some sample code. From what I've seen so far, I could learn to build a HTTP Server with C# or consume server sent events. But I found nothing about sending SSEs.
What I'm trying to get my head around: how can I keep sending updated data over the incoming request? Normally, you get a request, do your thing and reply. Done, connection closed. But in this case I want to kind of "stick" to the response-stream and send new data through, each time an event in my application fires.
The problem, for me, lies in this event-based approach: it's not some intervall-based polling and updating. It's rather that the app goes like "Hey, something happend. I really should tell you about it!"
TL;DR: how can I hold on to that response-stream and send updates - not based on loops or timers, but each time certain events fire?
Also, before I forget: I know, there are libraries out there doing just that. But from what I've seen so far (and from what I've understood; correct me if I'm wrong) those solutions depend on ASP.NET / MVC / you name it. And as I'm just writing a "plain" C# application, I don't think I meet these requirements.
As for a light-weight server I would go with an OWIN selfhost WebAPI (https://learn.microsoft.com/en-us/aspnet/web-api/overview/hosting-aspnet-web-api/use-owin-to-self-host-web-api).
A simple server-sent event server action would basically go like:
public class EventController : ApiController
{
public HttpResponseMessage GetEvents(CancellationToken clientDisconnectToken)
{
var response = Request.CreateResponse();
response.Content = new PushStreamContent(async (stream, httpContent, transportContext) =>
{
using (var writer = new StreamWriter(stream))
{
using (var consumer = new BlockingCollection<string>())
{
var eventGeneratorTask = EventGeneratorAsync(consumer, clientDisconnectToken);
foreach (var #event in consumer.GetConsumingEnumerable(clientDisconnectToken))
{
await writer.WriteLineAsync("data: " + #event);
await writer.WriteLineAsync();
await writer.FlushAsync();
}
await eventGeneratorTask;
}
}
}, "text/event-stream");
return response;
}
private async Task EventGeneratorAsync(BlockingCollection<string> producer, CancellationToken cancellationToken)
{
try
{
while (!cancellationToken.IsCancellationRequested)
{
producer.Add(DateTime.Now.ToString(), cancellationToken);
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
}
}
finally
{
producer.CompleteAdding();
}
}
}
The important part here is the PushStreamContent, which basically just sends the HTTP headers and then leaves the connection open to write the data when it is available.
In my example the events are generated in an extra-task which is given a producer-consumer collection and adds the events (here the current time every second) if they are available to the collection. Whenever a new event arrives GetConsumingEnumerable is automatically notified. The new event is then written in the proper server-sent event format to the stream and flushed. In practice you would need to send some pseudo-ping events every minute or so, as streams which are left open for a long time without data being sent over them would be closed by the OS/framework.
The sample client code to test this would go like:
Write the following code in async method.
using (var client = new HttpClient())
{
using (var stream = await client.GetStreamAsync("http://localhost:9000/api/event"))
{
using (var reader = new StreamReader(stream))
{
while (true)
{
Console.WriteLine(reader.ReadLine());
}
}
}
}
This sounds like a good fit for SignalR. Note SignalR is part of the ASP.NET family, however this does NOT require the ASP.NET framework (System.Web), or IIS, as mentioned in comments.
To clarify, SignalR is part of ASP.NET. According to their site:
ASP.NET is an open source web framework for building modern web apps
and services with .NET. ASP.NET creates websites based on HTML5, CSS,
and JavaScript that are simple, fast, and can scale to millions of
users.
SignalR has no hard dependency on System.Web or on IIS.
You can self-host your ASP.Net application (see https://learn.microsoft.com/en-us/aspnet/signalr/overview/deployment/tutorial-signalr-self-host). If you use .net core, it is actually self-hosted by default and runs as a normal console application.

Opening a websocket channel inside MVC controller

Has anyone has any good experience with opening a websocket connection inside MVC controller?
Technology stack: ASPNET Core 1.0 (RC1) MVC, dnx46, System.Net.WebSockets
Why MVC instead of middleware: for overall consistency, routing, already injected repositories, an option to call private methods in the same controller.
[HttpGet("v1/resources/{id}")]
public async Task<IActionResult> GetAsync(string id)
{
var resource = await this.repository.GetAsync(id);
if (resource == null)
{
return new HttpStatusCodeResult(404);
}
if (this.HttpContext.WebSockets.IsWebSocketRequest)
{
var webSocket = await this.HttpContext.WebSockets.AcceptWebSocketAsync();
if (webSocket != null && webSocket.State == WebSocketState.Open)
{
while (true)
{
var response = string.Format("Hello! Time {0}", System.DateTime.Now.ToString());
var bytes = System.Text.Encoding.UTF8.GetBytes(response);
await webSocket.SendAsync(new System.ArraySegment<byte>(bytes),
WebSocketMessageType.Text, true, CancellationToken.None);
await Task.Delay(2000);
}
}
}
return new HttpStatusCodeResult(101);
}
Question: are there any known downsides going with way instead of handling a websocket connections in a middleware? How about the handshake, do we need to do anything else in addition to returning HTTP 101 status code?
Update 1: why not SignalR? there is no need to use fallback techniques, so while it's a good product, it see no benefit of adding additional dependency in this situation.
Update 2: one downside I've already noticed - when the while(true) exists (for simplicity reasons, not shown in an example above, let' say, when a channel needs to be closed), the methods needs to return something (Task). What it should be? HTTP 200 status response? I guess no, because in the WebSockets documentation is written, that nothing should be sent after the "close" frame.
Update 3: one thing I learned the hard way, that if you want to get WebSockets working while debugging in Visual Studio 2015 using IIS Express 10.0 on Windows 10, you still have to use https://github.com/aspnet/WebSockets and configure app.UseWebSockets() in your Startup.cs file. Otherwise, IsWebSocketRequest will be false. Anyone knows why? Handshake?
Seems fine.
You probably want to change the while(true) to while (!HttpContext.RequestAborted.IsCancellationRequested) so you detect client disconnects and end the request.
You don't need to check for null or the state of the websocket after you call accept.
I'm assuming all of that code is temporary and you'll actually be reading something from the websocket.
All the usual websocket rules apply:
Use SSL (when you're hosting it forreal)
It won't work on multiple servers (it's a point to point socket connection)
You need to support handling partial frames. You can punt this if you know the client won't send any.

How to make the .net HttpClient use http 2.0?

I have an asp.net web api hosted on IIS 10 (windows server 2016). When I make a GET request to this from a Microsoft Edge browser, I see that HTTP 2.0 is used in IIS logs
2015-09-20 21:57:59 100.76.48.17 GET /RestController/Native - 443 - 73.181.195.76 HTTP/2.0 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/42.0.2311.135+Safari/537.36+Edge/12.10240 - 200 0 0 7299
However, when a GET request is made through a .net 4.6 client as below,
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://myapp.cloudapp.net/");
HttpResponseMessage response = await client.GetAsync("RestController/Native");
if (response.IsSuccessStatusCode)
{
await response.Content.CopyToAsync(new MemoryStream(buffer));
}
}
I see the following HTTP 1.1 log in the server logs
2015-09-20 20:57:41 100.76.48.17 GET /RestController/Native - 443 - 131.107.160.196 HTTP/1.1 - - 200 0 0 707
How can I make the .net client use HTTP/2.0 ?
1.Make sure you are on the latest version of Windows 10.
2.Install WinHttpHandler:
Install-Package System.Net.Http.WinHttpHandler
3.Extend WinHttpHandler to add http2.0 support:
public class Http2CustomHandler : WinHttpHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
request.Version = new Version("2.0");
return base.SendAsync(request, cancellationToken);
}
}
4.Pass above handler to the HttpClient constructor
using (var httpClient = new HttpClient(new Http2CustomHandler()))
{
// your custom code
}
In addition to WinHttpHandler (as described in Shawinder Sekhon's answer), .NET Core 3.0 includes HTTP/2 support in the default SocketsHttpHandler (#30740). Since HTTP/1.1 is still the default, either the default must be changed by setting HttpClient.DefaultRequestVersion, or Version must be changed on each request. The version can be set when the request message is created:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://myapp.cloudapp.net/");
HttpResponseMessage response = await client.SendAsync(
new HttpRequestMessage(HttpMethod.Get, "RestController/Native")
{
Version = HttpVersion.Version20,
});
if (response.IsSuccessStatusCode)
{
await response.Content.CopyToAsync(new MemoryStream(buffer));
}
}
Or by using a custom HttpMessageHandler, such as:
public class ForceHttp2Handler : DelegatingHandler
{
public ForceHttp2Handler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Version = HttpVersion.Version20;
return base.SendAsync(request, cancellationToken);
}
}
which can delegate to SocketsHttpHandler, WinHttpHandler, or any other HttpMessageHandler which supports HTTP/2:
using (var client = new HttpClient(new ForceHttp2Handler(new SocketsHttpHandler())))
{
client.BaseAddress = new Uri("https://myapp.cloudapp.net/");
HttpResponseMessage response = await client.GetAsync("RestController/Native");
if (response.IsSuccessStatusCode)
{
await response.Content.CopyToAsync(new MemoryStream(buffer));
}
}
HttpClient does not support HTTP/2 yet. It will be available in the next release (code name KATANA). Here is the link to their source code for the next release.
Till then, you could implement your own HttpMessageHandler object that implements HTTP/2 and pass it to the HttpClient's constructor (you probably can use their source code from KATANA).
HTTP/2 looks like it will be supported in C# client calls with .NET 4.6.2
https://msdn.microsoft.com/en-us/library/ms171868(v=vs.110).aspx
HTTP/2 Support (Windows 10)
HTTP/2 is a new version of the HTTP protocol that provides much better
connection utilization (fewer round-trips between client and server),
resulting in lower latency web page loading for users. Web pages (as
opposed to services) benefit the most from HTTP/2, since the protocol
optimizes for multiple artifacts being requested as part of a single
experience. HTTP/2 support has been added to ASP.NET in the .NET
Framework 4.6. Because networking functionality exists at multiple
layers, new features were required in Windows, in IIS, and in ASP.NET
to enable HTTP/2. You must be running on Windows 10 to use HTTP/2 with
ASP.NET.
HTTP/2 is also supported and on by default for Windows 10 Universal
Windows Platform (UWP) apps that use the System.Net.Http.HttpClient
API.

ASP.NET Web API: RC to RTM change. Sending content using HttpContext ends in a NoContent status

Since ASP.NET Web API RC I was using some approach based on declaring void API controller's operations.
I was customizing a response object DTO (instead of using HttpResponseMessage) using AOP and PostSharp, and finally this was sent to the client using HttpContext.Response.Write(...) serializing the DTO into a JSON string.
When I upgraded my solution to ASP.NET Web API RTM, this approach didn't work anymore.
Whenever I send a response from the Web API and I receive it in the client-side, I find that the response is sent with a 204 status (NoContent) while I was setting a 200 status (OK) for the response itself.
Because this approach was working in the RC version of WebAPI I suspect that's an unknown breaking change when WebAPI development team transitioned to RTM version.
Am I wrong?
As far as I know, since RTM if a POST action does not return an HttpResponseMessage the default status code is 204 (and not 200 as was back in RC). There are two things, I know, we can do to keep clients from complaining about 204.
a) Change the response message from within your action:
[HttpPost]
public HttpResponseMessage DoWork(MyModel model)
{
// Do work
return new HttpResponseMessage(HttpStatusCode.OK) { Content = new ObjectContent<MyModel>(model, FormatterConfig.JsonFormatter) };
}
b) Change the response in a DelegatingHandler (dirty by generic way)
public class ResponseHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = base.SendAsync(request, cancellationToken);
response.Result.StatusCode = response.Result.IsSuccessStatusCode ? System.Net.HttpStatusCode.OK : response.Result.StatusCode;
return response;
}
}
I am not aware of such breaking change but I can confirm that this doesn't work in the RTM. Anyway, that's such a wrong approach of using the Web API that it's probably a good thing that it doesn't work. You are killing the whole point of the Web API if you are going to manually write the response to the client. If you have some existing code that does this that you cannot modify then I would recommend you using a Generic ASHX handler until you are ready to upgrade.

WebClient class doesn't exist in Windows 8

I want to use a HTTP webservice, and I've already developed an app for wp7.
I use the WebClient class, but I can not use it for windows 8 ("error: type or namespace can not be found").
What else can I use?
Can you provide me a sample of code?
Does Microsoft have a site to help when a namespace don't exist?
Option 1 : HttpClient if you don't need deterministic progress notification this is what you want use. Example.
public async Task<string> MakeWebRequest()
{
HttpClient http = new System.Net.Http.HttpClient();
HttpResponseMessage response = await http.GetAsync("http://www.example.com");
return await response.Content.ReadAsStringAsync();
}
Option 2: When you need progress notifications you can use DownloadOperation or BackgroundDownloader. This sample on MSDN is a good start.
Option 3: Since you mentioned web service and if it is returning XML you can use XmlDocument.LoadFromUriAsync which will return you an XML document. Example
public async void DownloadXMLDocument()
{
Uri uri = new Uri("http://example.com/sample.xml");
XmlDocument xmlDocument = await XmlDocument.LoadFromUriAsync(uri);
//do something with the xmlDocument.
}
When you are developing for metro .Net framework will be limited compared to the desktop version. If you see namespace not found error it is usually due to this fact. This link on the MSDN has the list of namespaces, classes available for metro.

Categories