In Signalr .net core - where should validation take place? - c#

If I have a hub method that accepts parameters
e.g.
public IObservable<MyStreamItem> StreamData(SomeRequestData request)
{}
How do I propogate validation errors in the request?
An actual http request is only made when the socket connection is established.
So subsequent calls to Hub methods dont pass through any middleware. They are just frames/messages in the open websocket.
I've had a look at this package which is for the previous version of Signalr (for the full .net framework)
https://github.com/AGiorgetti/SignalR.Validation
This uses a HubPipelineModule which doesn't seem to exist in the new .net core Signalr.
Is there an appropriate place in the pipeline that I can tap into to do the validation?
Or should it be done in the hub method itself? And if so, how would you conditionally return a structured set of errors, as opposed to what the actual return type is meant to be?
thanks

There are currently no HubPipelineModules in SignalR alpha but we're looking at an equivalent for preview 2. Today, you'd need to do it in the method and potentially throw an error to get it back to the client.

Related

Problems calling ServiceStack services in-process with Validation & Filters

I need to be able to call my SS services from the controllers of an MVC application. Ideally i'd like to call them in-process to avoid the overhead of buiding a http request etc.
From scouring documentation I feel there are 2 suggested methods, but neither work fully.
1) ServiceGateway - Use the service gateway. This calls validation filters, but does not call other customer filters I've added. No option to applyFilters.
2) HostContext.ServiceController.Execute - There is a dedicated option on this method called applyFilters, and when I set it to true it works and applies filters and validation (though it only executes GlobalFilters, not TypedRequestFilters). However, if [CacheResponse] attribute is set on the service it overwrites and flushes a response to my client overriding the flow of the MVC controller and i don't know how to stop this. It does not do this if I set to applyFilters to false or if I take CacheResponse off. Changing the priority of the cache has no effect.
I'm calling the Execute method as follows from within an Action method on my controller:
HostContext.ServiceController.Execute(serviceRequest, HostContext.GetCurrentRequest(), true);
Before this method even returns control a response is flushed to the webpage on Chrome and then nothing/null is returned from method.
I feel there is regarding point 1) a feature missing and point 2) a bug in the implementation, though am not confident enough in my knowledge of SS to remedy either! Please help!
Thanks.
Filters are executed as part of the HTTP Request Pipeline and can terminate the current Request with a custom HTTP Response. You can check IRequest.IsClosed after executing the Request to check if it has been terminated by a Request Filter. They're behavior is incompatible with internal Gateway requests so there's no option to execute them in the Gateway.
I've marked these ServiceController methods as an In Process Request in this commit which should resolve the issue with the [CacheResponse] attribute which ignores In Process Requests.
This change is available from v4.5.13 that's now available on MyGet.

Failure to deserialize with [FromBody] tag

I'm got an api endpoint I'm trying to hit that uses the [FromBody] tag with an object in the parameter line like so:
[HttpPost]
[Route("update")]
public IHttpActionResult MyWebApiMethod([FromBody] MyObject objectValue)
{
I've been writing a UWP app that communicates with this web api, and I've successfully hit the endpoint just fine before; however, for whatever reason, as of lately, I can no longer hit this specific endpoint. The controller for the api initiliazes, and when I enable tracing, I can see the controller has managed to associate the correct endpoint, and seems to have deduced that the data model of the object I'm sending matches the one the api is expecting, but when it goes to do the deserialization as a result of the [FromBody] tag, it just goes into never never land, and doesn't do anything. Eventually my app times out with its request.
Out of many tests I did to try and resolve what was causing this issue. I found 2 notable things, but I can't figure out how to fix the root issue.
First off, was a temporary workaround. If I changed the endpoint to receive a JObject instead and used
var newValue = JsonConvert.DeserializeObject<MyObject>(JsonConvert.Serialize(objectValue);
then, the endpoint would get hit, and my newValue would be properly deserialized.
Second, going with the chance that my datamodel on the client was different than the one our api was using, I turned the data model into a nuget (I'm having issues making this nuget compatible for Universal Windows 10 apps due to some reference issues, so I made a normal Class Library) then install the nuget into a fairly bare bones console application, and made the same call to the same endpoint, and it hit the end point fine without having to resort to using JObject in the method parameter.
So, somewhere, somehow, the deserialization process happening when the data packet comes from a Universal app is different than the one coming from a generic console application. Unfortunately, I can't figure out how to tie into this deserialization process when the [FromBody] takes over before going into the Method.
Any help on resolving this issue would be great.

Handling multiple subprotocols with System.Net.WebSockets

What is the correct way for a WebSockets server using HttpListener and System.Net.WebSockets to support multiple subprotocols?
I am using HttpListener to create an HttpListenerContext. On receiving a request with IsWebSocketRequest true the code calls AcceptWebSocketAsync with the subprotocol name as the parameter.
If the client request is for a different subprotocol then an exception is raised, which is to be expected.
There's no version of AcceptWebSocketAsync() that accepts a list of subprotocols and if I make two asynchronous calls to AcceptWebSocketAsync() with different subprotocols, only the latter is effective.
Edit 14 March
To clarify, I'm looking for support for the Sec-WebSocket-Protocol header such that the framework accepts a websockets upgrade based on finding a common subprotocol between those requested by the client and those supported by the server, and then tells the calling code in some way which (single) subprotocol has been agreed. (For example, in libwebsockets, you provide one callback per subprotocol.)
You have access to HttpListenerContext which has the Request property. It returns an instance of HttpListenerRequest which in turn has the Headers property. Headers returns a collection of name/value pairs. You should find there Sec-WebSocket-Protocol header.
Now you have the list of subprotocols requested by a client. You also know what subprotocols are known by a server so you easily perform matching.
However, to be honest I didn't try this approach and I'm aware that it is not a straightforward solution.

SignalR kills IIS Express when returning a List of objects

We have a MongoDB-based trace system and a Web Trace Viewer (ASP.NET 4.0, c#, MVC 4). One of the options of this Trace Viewer is follow the tail. I've implemented it via javascript polling but thought I could use it to learn SignalR.
I've made a local copy, updated it to .NET 4.5 and installed SignalR via nuget(VS 2013). I've been following the guide at Tutorial: Server Broadcast with SignalR 2 and documentation from ASP.NET SignalR Hubs API Guide - Server (C#). This guide states that
You can specify a return type and parameters, including complex types and arrays, as you would in any C# method. Any data that you receive in parameters or return to the caller is communicated between the client and the server by using JSON, and SignalR handles the binding of complex objects and arrays of objects automatically
and
[when you call client methods from the Hub class] You can specify complex types and arrays for the parameters.
The TraceModel is a simple class with several public strings (as category, message, server) and a DateTime created. My core process is:
IEnumerable<TraceModel> traces = GetTracesTail();
if (traces.Any())
{
BroadcastTracesTail(traces);
}
private void BroadcastTracesTail(IEnumerable<TraceModel> tail) {
connectedClients.All.updateTail(tail);
}
and it fails (and forces the IIS Express server to shut down) when it has to return an IEnumerable (I've tried also returning a List but it still fails). It will NOT fail in the following case:
private void BroadcastTracesTail(IEnumerable<TraceModel> tail) {
connectedClients.All.updateTail(tail.Count());
}
So I assume it must be a problem with my JSON parser or my IIS express, but I don't know how to test nor fix it. Any help will be apreciated.
Well, it was a problem with the json serializer and my short-sightedness: I didn't realize that my TraceModel had a Bson.ObjectId field (because it comes from MongoDB) which is not serializable. I've changed it to string and now it serializes beautifully.
Thanks to welegan for the comments.

Is RequestFilter Validation client dependent?

Should I expect Request Filter Validation (e.g. FluentValidation) to be triggered when instantiating a reference service via AppHostBase.ResolveService<>?
Thus far, I've only successfully received proper error responses to my C# application when using the typed clients (JsonServiceClient in this case specifically).
You are right. If you try use AppHostBase.ResolveService<T> it does not execute any of the registered request filters. Essentially it only resolves the Service from the AppHost dependancy container, you get back just the Service instance. Thus your validators aren't triggered.
ServiceStack v4:
As #mythz points out you can use the MQ entry point API of the HostContext to execute the call with the MQ request filters and thus have the validation run. To do this:
HostContext.ServiceController.ExecuteMessage(new Message<T>(requestDto), httpReq);
#mythz also notes you can execute a service using just a DTO, rather than having to determine the service and handling method to call, but in a similar fashion to AppHostBase.ResolveService<T> it doesn't trigger the request filters. Usage:
HostContext.ServiceController.Execute(requestDto, httpReq)
ServiceStack v3:
GetAppHost().Config.ServiceManager.ServiceController.ExecuteMessage(new Message<T>(requestDto), httpReq);

Categories