I am using SignalR 1.1 with .NET clients.
I have a single method in my hub that accepts an object of BaseMessage class and broadcasts it to all clients:
public void SendMessage(BaseMessage message)
{
Clients.All.BroadCastMessage(message);
}
Clients will pass derived messages into this method:
_hub.Invoke("SendMessage", new ErrorMessage("Some Error")).Wait();
The client has a single message handler:
_hub.On<BaseMessage>("BroadCastMessage", OnMessageReceived);
I've specified TypeNameHandling.All serializer settings at application startup:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All};
var serializer = new JsonNetSerializer(settings);
GlobalHost.DependencyResolver.Register(typeof(IJsonSerializer), () => serializer);
But when the client sends a derived message, the server receives a base message.
How should I configure serializer to be able to receive derived messages?
Note: I can do serialization/deserialization manually and pass strings to the server, but this causes double serialization.
SignalR is not supporting this scenario as it would require your JSON payload to contain information about the derived type and assembly. See this sample.
Adding type information in your payload would not play well with browsers. I suggest you create individual hub methods to handle each of your derived types.
Related
Just trying to wrap my mind around handling pushing data to some users through SignalR.
Say, in a private chat situation, Person A sends a message to Person B. If I'm understanding the concept correctly, I need to create a Group for each user who logged into the system. This way, when the new message from Person A comes in, in my SignalR Hub, I'd send the message to the group for Person B which only has only one user in it i.e. Person B.
In this approach, I'd essentially create a unique Group for each user so that I have the flexibility to push data to each unique user. I could use the UserId as the Group Id.
Is this the way to handle pushing data selectively to each unique user?
You can grab client Ids manully like so and then send them using the hubcontext to avoid creating a lot of groups (you just need to implement a menthod which get you're connections from your resource in my case im using dtos)
I'm assuming your hubs have some type of connection manager, here's a sample of one from the docs
In my case I have a dynamic configuration which I use to configure my hubs using the Type of DTO, and I send hubs using a generic hub base here is a sample implementation:
Warning: things may slightly be different I'm using .Net-Core in this example
//NOTE: THub must be the one Registered with MapHubs in the Startup
//class or your connections won't be there because Hubs are not contravarient
public abstract class HubBase<TDTO, THub> : Hub
Where THub: HubBase<TDTO, THub>
{
protected IHubContext<THub> hubContext;
HubBase(IHubContext<THub> hubContext)
{
this._hubContext = hubContext;
}
protected abstract List<string> GetConnectionsByDto(TDTO dto)
protected async Task SendFilteredAsync(string eventName, TDTO dto)
{
var clientIds = await this.GetConnectionsByDto(dto);
if (false == clientIds.Any())
{
return;
}
var broadcastTasks = clientIds.Select(async clientId =>
await this._hubContext.Clients.Client(clientId).SendAsync(eventName, dto));
await Task.WhenAll(broadcastTasks);
}
}
So, I've registered a named client with the services collection in my Startup.cs:
services.AddHttpClient(someServiceName,
client => client.BaseAddress = baseAddress);
and now can inject an IHttpClientFactory from my service provider.
Using this IHttpClientFactory, I conjure up a client instance:
var client = httpClientFactory.CreateClient(someServiceName)
Once upon a time, it was necessary to be very careful about the disposing of HttpClient instances, as it was rarely the right thing to do.
However, now we have HttpClientFactory, does this matter any more? Should/Can this client be disposed without worry? e.g.
using (var httpClient = httpClientFactory.CreateClient(someServiceName))
using (var response = await httpClient.PostAsync(somePath, someData))
{
var content = await response.Content.ReadAsAsync<SomeResponse>();
//...
}
Calling the Dispose method is not required but you can still call it if you need for some reasons.
Proof: HttpClient and lifetime management
Disposal of the client isn't required. Disposal cancels outgoing requests and guarantees the given HttpClient instance can't be used after calling Dispose. IHttpClientFactory tracks and disposes resources used by HttpClient instances. The HttpClient instances can generally be treated as .NET objects not requiring disposal.
Check the source of DefaultHttpClientFactory:
public HttpClient CreateClient(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
var handler = CreateHandler(name);
var client = new HttpClient(handler, disposeHandler: false);
var options = _optionsMonitor.Get(name);
for (var i = 0; i < options.HttpClientActions.Count; i++)
{
options.HttpClientActions[i](client);
}
return client;
}
The instance of HttpMessageHandler stores unmanaged resources of the HttpClient. In the classical scenario the HttpClient creates the instance of HttpMessageHandler and disposes it while itself disposing.
You can see in the above code that different instances of HttpClient shares single instance of HttpMessageHandler and doesn't dispose it (disposeHandler: false).
So, the call of the HttpClient.Dispose does nothing. But it's not dangerous.
No. You should not dispose of your client. To be more general, you should not dispose of anything retrieved via a DI container, which in ASP.NET Core is by default the service collection. The lifetime is managed by the DI container, so if you dispose of the client, but it's later injected into something, you'll get an ObjectDisposedException. Let the container handle disposal.
This is actually a common confusion with IDisposable classes. You should personally only implement IDisposable if your class itself owns dependencies. If all its dependencies are injected, you should not implement IDisposable, since it doesn't own anything that needs disposal. Likewise, you should not dispose of anything injected into your class, as it doesn't own those dependencies. Only dispose of things you specifically new up. If you don't see the keyword new, you probably shouldn't be disposing.
Is there a way to configure App Insights to collect the operation name when monitoring a WCF service? All requests get lumped together by URL (which are just POSTs that end in .svc), so there is no easy way to determine which particular operation was called on the service.
Does there need to be a custom Telemetry Initializer that can somehow determine which operation was actually called and set a custom property? if so, how do you determine the current WCF operation name?
Another option for collecting data on WCF operations is to use the Microsoft.ApplicationInsights.Wcf Nuget package. You can read more about this here.
Brett,
Operation name can be customized in two ways:
1) Using a custom telemetry initializer - that specifically sets operation name.
For more information about telemetry initializers: Custom Telemetry Initializers
2) From sdk version 2-beta3, auto-generated request telemetry is accessible though HttpContext extension method:
System.Web.HttpContextExtension.GetRequestTelemetry
Once the request telemetry is retrieved, operation name associated with it can be changed.
Please let me know if this addressed your question.
Thanks,
Karthik
If you want to get the name of the WCF method called from a client in application insight you can use the following ITelemetryInitializer
With .net 5.0, the httprequest object is stored in the raw object properties of the telemetry context.
public class SoapActionHeaderTelemetryInitializer : ITelemetryInitializer
{
private static readonly Regex _soapActionUri = new Regex("^\"(?<uri>.*)\"$", RegexOptions.Compiled);
public void Initialize(ITelemetry telemetry)
{
DependencyTelemetry httpDependency = telemetry as DependencyTelemetry;
if (httpDependency != null)
{
httpDependency.Context.TryGetRawObject("HttpRequest", out var request);
if (request is HttpRequestMessage httpRequest)
{
if (httpRequest.Headers.TryGetValues("SOAPAction", out var values) && values.Any())
{
// SOAP Action is contained within quote : https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383528
var soapAction = _soapActionUri.Match(values.First()).Groups["uri"].Value;
telemetry.Context.GlobalProperties["SOAPAction"] = soapAction;
}
}
}
}
}
I have a web application. I found that performance bottleneck could be that i am creating Http client again and again for every request.
public static class DemoHttpClient
{
public static HttpClient GetClient()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(DemoConstants.DemoAPI);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
}
public class DemoConstants
{
public const string DemoAPI = "http://localhost/";
}
I am planning to implement singleton for this. And found this very helpful article.
http://csharpindepth.com/Articles/General/Singleton.aspx
I am confused as to how exactly ASP.NET MVC web application lifecycle is with when it is deployed on the server. Assuming there will be multiple threads calling same resource, the resource further again and again making new http clients..
What should we do here..
1) Lazily load HTTP client?
2) Not lazily load it?
Which particular approach should we use?
This doesn't sound like a good idea. In particular, take a peek into the docs of the HttpClient class:
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
https://msdn.microsoft.com/en-us/library/system.net.http.httpclient%28v=vs.118%29.aspx
This means that accessing the very same singleton instance from multiple threads will lead to undefined issues.
What you could do however, is you could reuse the same instance across a single request. This can be done by storing an instance in the Items container:
private static string ITEMSKEY = "____hclient";
public static HttpClient GetClient()
{
if ( HttpContext.Current.Items[ITEMSKEY] == null )
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(DemoConstants.DemoAPI);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpContext.Current.Items.Add( ITEMSKEY, client );
}
return (HttpClient)HttpContext.Current.Items[ITEMSKEY];
}
Note, that since the HttpClient implements IDisposable, it still could be a good idea to dispose such instance somewhere in the pipeline, for example in the EndRequest event of the application pipeline.
Update: as noted in a comment by #LukeH, the updated version of the docs for the .NET 4.5 and 4.6 states that some of methods of the HttpClient class are thread safe:
https://msdn.microsoft.com/en-us/library/system.net.http.httpclient%28v=vs.110%29.aspx
The updated remarks section states that a single instance is basically a collection of shared settings applied to all requests executed by this instance. Then, the docs says:
In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.
This means that the isolation of different pools could still make sense, my personal recommendation would still be then to not to have a singleton, as you possibly would still need to change some settings between consecutive requests.
In our api we are using spring Jackson http message converter to automatically convert java object to json. I am enjoying that feature,but what I personally feel is that I've lost control over the response http status code.if I want to return the response with different status codes ,I have the choice of using #responsestatus(httpstatus),but I cannot specify the status dynamically,as annotation is expecting a enum const expression. The other choice is http server response.set status(),but I don't like that.spring's responseentity(jsonstring,statuscode) is a great thing to solve but if I want to use Jackson httpmessageconverter is any way to configure the response status code dynamically.
You can return ResponseEntity<MyObject> from your controller method and it will still use the configured message converters, example:
#RestController
#RequestMapping("/foo")
public class FooController {
#RequestMapping
public ResponseEntity<MyObject> foo() {
MyObject myObject = new MyObject();
// You can dynamically set the status based on your needs
HttpStatus status = HttpStatus.OK;
return new ResponseEntity<>(myObject, status);
}
}