is there any way to get current signalR request user outside the hub? I can use Hub.Context.User inside of hub methods, but if hub method calls any other underlying layer? Wcf service call - an additional BehaviorExtensionElement is used to add wcf message header with current user identity name.
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
request.Headers.Add(MessageHeader.CreateHeader(
Constants.HeaderNames.SessionId,
Constants.HeaderNames.HeaderNamespace,
_hubManager.ResolveHub(Constants.Hubs.MessengerHub).
Context.User.Identity.Name));
}
Yes, i found that the DefaultHubManager gets the Hub, but i'm not sure it will be the hub from current request, not the concurrent one or a new one, 'cause at the end of ResolveHub i see the following code runs
return (DependencyResolverExtensions.Resolve(this._resolver, descriptor.HubType)
?? Activator.CreateInstance(descriptor.HubType)) as IHub;
Obviuosly i can pass user from hub method to wcf call but it requires refactoring to move from wcf behaviour to setting request field with user name explicitly.
Also can i rely on HttpContext.Current to get the info from cookie?
No you cannot. The only way to retrieve the currently active user outside of the hub itself would be to pass the users information to whatever method you call in the hub.
A common pattern is to track your users by adding them to some sort of dictionary in OnConnected and removing them in OnDisconnected. You can then have an entirely separate way of identifying your users while having required information that's associated with them.
Related
I want to be able to send message to specific user account with SignalR.
Right now I can send to everyone!
I am looking for any way to have access to context.ConnectionID in controller outside of hub. I tried accessing it inside of controller with iHubContext and inside of hub I tried to save value of connectionID in session but both are not supported.
What would be best way to access connectionID from Controller outside of Hub?
here is action method from ChatController that is used for sending message to everyone
public IActionResult PosaljiPoruku()
{
_hubContext.Clients.All.SendAsync("PrimljenaPoruka", "aaa");
return PartialView("SubmitFormPartial");
}
Any help is appreciated!
Thanks for trying to help!
What would be best way to access connectionID from Controller outside of Hub?
From this doc about sending messages from outside a hub, you would find:
When hub methods are called from outside of the Hub class, there's no caller associated with the invocation. Therefore, there's no access to the ConnectionId, Caller, and Others properties.
I want to be able to send message to specific user account with SignalR.
You can mapping user and ConnectionId(s) while client connected to Hub server, then if you want to send message to specific user from controller action outside of your Hub, you can query mapping table to get corresponding connection Id(s) first based on user name etc, and passing connection Id(s) to action method.
await _hubContext.Clients.Client("connection_id_here").SendAsync("PrimljenaPoruka", "aaa");
Besides, you can achieve same by creating single-user group (a group for each user), and then send a message to that group when you want to reach only that specific user.
await _hubContext.Clients.Group("group_name_here").SendAsync("PrimljenaPoruka", "aaa");
Just getting my head around message queues and Redis MQ, excellent framework.
I understand that you have to use .RegisterHandler(...) to determine which handler will process the type of message/event that is in the message queue.
So if I have EventA, EventB etc should I have one Service which handles each of those Events, like :
public class DomainService : Service {
public object Any(EventA eventA) {...}
public object Any(EventB eventA) {...}
}
So these should be only queue/redis list created?
Also, what If I want a chain of events to happen, so for example a message of type EventA also has a handler that sends an Email providing handlers earlier on the chain are successful?
ServiceStack has no distinction between services created for MQ's, REST, HTML or SOAP services, they're the same thing. i.e. they each accept a Request DTO and optionally return a Response DTO and the same service can handle calls from any endpoint or format, e.g HTML, REST, SOAP or MQ.
Refer to ServiceStack's Architecture diagram to see how MQ fits in.
Limitations
The only things you need to keep in mind are:
Like SOAP, MQ's only support 1 Verb so your methods need to be named Post or Any
Only Action Filters are executed (i.e. not Global or Attribute filters)
You get MqRequest and MqResponse stubs in place of IHttpRequest, IHttpResponse. You can still use .Items to pass data through the request pipeline but any HTTP actions like setting cookies or HTTP Headers are benign
Configuring a Redis MQ Host
The MQ Host itself is completely decoupled from the rest of the ServiceStack framework, who doesn't know the MQ exists until you pass the message into ServiceStack yourself, which is commonly done inside your registered handler, e.g:
var redisFactory = new PooledRedisClientManager("localhost:6379");
var mqHost = new RedisMqServer(redisFactory, retryCount:2);
mqHost.RegisterHandler<Hello>(m => {
return this.ServiceController.ExecuteMessage(m);
});
//shorter version:
//mqHost.RegisterHandler<Hello>(ServiceController.ExecuteMessage);
mqHost.Start(); //Starts listening for messages
In your RegisterHandler<T> you specify the type of Request you want it to listen for.
By default you can only Register a single handler for each message and in ServiceStack a Request is tied to a known Service implementation, in the case of MQ's it's looking for a method signature first matching: Post(Hello) and if that doesn't exist it looks for the fallback Any(Hello).
Can add multiple handlers per message yourself
If you want to invoke multiple handlers then you would just maintain your own List<Handler> and just go through and execute them all when a request comes in.
Calling different services
If you want to call a different service, just translate it to a different Request DTO and pass that to the ServiceController instead.
When a MQ Request is sent by anyone, e.g:
mqClient.Publish(new Hello { Name = "Client" });
Your handler is invoked with an instance of type IMessage where the Request DTO is contained in the Body property. At that point you can choose to discard the message, validate it or alter it.
MQ Requests are the same as any other Service requests
In most cases you would typically just forward the message on to the ServiceController to process, the implementation of which is:
public object ExecuteMessage<T>(IMessage<T> mqMsg)
{
return Execute(mqMsg.Body, new MqRequestContext(this.Resolver, mqMsg));
}
The implementation just extracts the Request DTO from the mqMsg.Body and processes that message as a normal service being passed a C# Request DTO from that point on, with a MqRequestContext that contains the MQ IHttpRequest, IHttpResponse stubs.
I am consuming one java webservice with WCF client.
I want to pass user related information to service in header. I have aleady gone to through thread
How to add a custom header to every WCF calls?
I have implemented IClientMessageInspector interface with BeforeSendRequest() method. Now, I want to pass user related information in SOAP header like Oraganization, which may differ for every user. I have all this information in my ASP.net application, which uses this service.
Is there anyway I can pass user related information to this BeforeSendRequest() method from asp.net session and build Message header before sending any request?
There are few options
Put the information in Session and retrieve it in BeforeSendRequest
Put it in HttpContext.Current.Items and retrieve it in `BeforeSendRequest'
Use Thread Local Storage (http://msdn.microsoft.com/en-us/library/6sby1byh.aspx)
It seems like I'm barking up the wrong tree when asking this question, this question and this question.
I need to authenticate users against a custom API (in COM), and I need to keep that custom API (the COM object) alive (for that user) for future WCF calls. During authentication against that custom API, I can get back a list of custom-defined roles. I'd also like to use these for authorization of the service methods.
Moreover, I need to be able to revoke the user's session remotely. This is triggered by an event raised by the COM API.
I've got a custom UserNamePasswordValidator, but it appears that this has no mechanism for correctly setting a custom principal, so it looks like I'm heading in the wrong direction.
How do I do these three things?
You can handle authentication completely in your service. Create service contract similar to:
[ServiceContract(SessionMode=SessionMode.Required)]
public interface IService
{
// All your operations marked with [OperationContract(IsInitiating=false, IsTerminating=false)]
// Two additional operations
[OperationContract(IsInitiating=true, IsTerminating=false)]
void Login(string user, string password);
[OperationContract(IsInitiating=false, IsTerminating=true)]
void Logout();
}
Service implementing this contract has to have PerSession instancing. Implement authentication in Login method and store COM object in local field. When new client want to use such service he has to first call the Login method. So all your instances will be properly authenticated and they will store their instance of COM object.
You can also register InstanceContext and COM object to some global class which will deal with forcibly killing service instance. This will probably require some research to make it work.
Make sure that you use some secure binding (encryption) because you will send user name and password as a plain text.
From a little bit of reading around, it is my understanding that the only way to detect that a client has connected to my service is through writing my own code. I am using a Singleton service. I would like to display a message every time a client connects to my service that client x with ip xxx has connected. There is no built-in event that is generated? Am I correct?
No, I don't think there's any support in WCF for your requirement.
Not sure what you want to achieve with this, either. Your service class (in your case, just a single instance) really doesn't have any business putting up messages (on screen, I presume) - that really not it's job. The service class is used to handle a request and deliver a response - nothing more.
The ServiceHost class might be more of a candidate for this feature - but again, it's job really is to host the service, spin up the WCF runtime etc. - and it's really not a UI component, either.
What you could possibly do is this
have an Admin UI (a Winforms, console, or WPF app) running on your server alongside your service, providing an admin service to call
define a fast connection between the two services (using e.g. netNamedPipe binding which is perfect for intra-application messaging)
when your "real" service gets a call, the first thing it does is send out a message to the admin UI which can then pick up that message and handle it
That way, you could cleanly separate your real service and it's job (to provide that service) and the Admin UI stuff you want to do and build a cleanly separated system.
I have actually implemented my own connect, disconnect and ping service methods which I manually call from my client once the channel has been created. By using them as a kind of header section in all of my ServiceContract interface definitions (and their implementations, of course), they form an makeshift "base service definition" that only requires a bit of cut-n-paste.
The string-based parameters of connect and disconnect will be used to send client info to the server and return server info and (perhaps a unique connection id) to the client. In addition a set of timing reference points may make its way in also.
Note how SessionMode is required and the individual OperationContract properties IsInitiating and IsTerminating are explicitly specified for each method, the end result being what I would call a "single-session" service in that it defines connect and disconnect as the sole session bookends.
Note also that the ping command will be used as the target of a timer-based "heartbeat" call that tests the service connection state and defeats ALL connection timeouts without a single config file :-)
Note also that I haven't determined my fault-handling structure yet which may very well add a method or more and/or require other kinds of changes.
[ServiceContract( SessionMode = SessionMode.Required )]
public interface IRePropDalSvr {
[OperationContract( IsInitiating=true, IsTerminating=false )]
string connect (string pClientInfo);
[OperationContract( IsInitiating=false, IsTerminating=true, IsOneWay=true )]
void disconnect (string pClientInfo);
// ------------------------------------------------------------------------------------------
[OperationContract( IsInitiating=false, IsTerminating=false )]
string ping (string pInp);
// ------------------------------------------------------------------------------------------
// REST OF ServiceContract DEFINITION GOES HERE
One caveat: while I am currently using this code and its implemention in my service classes, I have not verified the code yet.