I have a question, how can i get userId from Application controller? I saw many samples, how to get it from Hubs. But i don't know how can i call hub from controller in other way then
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
in the context i havent any id.
I saw samples like that, here i can call context and get UserId, but this works only in the Hub.
var name = context.User.Identity.Name;
I know that i can do something like that:
public class MyHub : Hub
{
public void Send(string userId, string message)
{
Clients.User(userId).send(message);
}
}
But i have to call hub from the controller.
Thanks for help
May I suggest a slightly different approach. In general that poking into the the hub from outside the signalr context doesn't work well or at least makes things more complicated.
You could have the controller act as client to the hub itself and expose the information you need via the hub to the controller. All you'd need is the SignalR Desktop Client package. While it adds an overhead, you'll have a much more compliant way for data retreivement and as a benefit a nice separation of concerns.
Here's a similar question that I replied to. HTH.
If you have some kind of authentication in your application, a good idea might be keeping a mapping between users and connections.
This way, whenever you want to send a message to a user, simply retrieve all that user's connectin IDs and send the message to all of them.
foreach(var connectionId in UserMapping)
context.Clints.Client(connectionId).sendMessage(message);
This way, you are able to send messages to specific clients from outside the hub and you are sure that all instances of the client get notified.
Take a look here for more information on Mapping SignalR Users to Connections.
Hope this helps.
Best of luck!
i found a solution.
By the way, thanks for your answers.
I try to use signalR from class which was calling by the application controller.
In the class i haven't got any context and special data about user who called server.
But i found into the controller info about which user calling the server.
this.User.Identity.Name
Happy coding ;)
Related
I'm planning on implementing a single-page application in Rails/AngularJS which also has some pieces that are exposed as a "public" API. My question is, what's the best way to architect the two APIs in such an application? E.g. Is it wise to have them both housed/versioned in the same namespace, or should they be kept separate somehow?
This is relatively new territory for me, but at first blush it seems like providing a single API covering both internal and external needs, then parsing up which pieces are available via some kind of authorization system based on the provided token would be the best way of going about this.
Is this the right direction, or would you recommend some other path?
FWIW, I will give you my opinion.
CAVEAT: I'm not a rails guy so I'm coming at this from nodejs/expressjs land.
There are many ways to skin this cat, but I'll just say that you are headed in the right direction. if you want to look at a very opinionated way to do things (and one people might hate) in node, see this: https://github.com/DaftMonk/fullstack-demo/blob/master/server/api/user/index.js. here you see this bit:
var router = express.Router();
router.get('/', auth.hasRole('admin'), controller.index);
router.delete('/:id', auth.hasRole('admin'), controller.destroy);
router.get('/me', auth.isAuthenticated(), controller.me);
router.put('/:id/password', auth.isAuthenticated(), controller.changePassword);
router.get('/:id', auth.isAuthenticated(), controller.show);
router.post('/', controller.create);
these routes correspond to calls to http:/serverurl/api/user/ etc. obviously, these are all checking authentication, but you could easily create a resource route that didn't need to check for authentication before passing control to the controller and (eventually) sending back a resource.
the approach this takes is to have middleware on the server check for auth tokens to make sure the client can call the api. without making you look into the code too much, i'll just give you a basic rundown.
client(requests Auth)->server(approves passes back token)->client(stores token)
LATER:
client(requests api call sends token in request)->server(passes request to middleware that checks token to make sure its kosher)->server(sends back resource and token)->client(uses resource and stores token)
then the whole thing repeats.
as far as whether to have separate apis vs one namespace, i don't have a very strong opinion. it really depends on how you structure your app. if you know in advance what resources will be public, then its probably easy to create a namespaced api.
angular can easily adapt to multiple api calls. you can create services for your public vs private http calls (or whatever way you decide to call the api.)
hope this was somewhat helpful! sorry its not railsy! (but nodejs/express is awesome!)
I managed to create a chat application using SignalR and Asp.NET.
My next objective is to send and accept friend request.
Could anyone suggest some good sites/forums where I can get help regarding this.
Thanks
You need to think about this from a system design standpoint prior to approaching a solution directly with ASP.NET and SignalR. Some of the things you need to consider and decide on are:
How will one user be associated to another user in order to create a friendship? (ex: new table to group two users)
How should friend requests be made?
How will friend request denials work?
Once you start brainstorming on how you would want this all to work, you can then build it out on the server side prior to ever getting into SignalR. Assure all areas of functionality work appropriately and then you can expose these method calls to your clients front-end through SignalR.
The key is to break down each part of the process into components and working on it one step at a time.
to send friend request to specific user use hub method
Clients.Client(toConnectTo).sendRequest(currentname+" SentYouFriendRequest");
and call it on client
chat.client.sendRequest = function (msg) {
$('#sentmsg').append('<li>'+msg+'</li>');
};
How would I use breeze against an odata service using only the
server's metadata to define the model? Will the context still be
able to handle crud operations to a non web api service?
I have seen
// service name is route to the Web API controller
var serviceName = 'api/CarBones';
/*** dataservice proper ***/
// manager (aka context) is the service gateway and cache holder
var manager = new entityModel.EntityManager(serviceName);
Can I do something like replacing the serviceName with an oData uri
and then continue using breeze as usual?
var serviceName = "http://localhost:1234/Northwind.svc"
Thanks for your help!
This question was posted by jpirok on our IdeaBlade forums. I am reposting the question and answer here since I think it will be useful to the Breeze Stack Overflow community.
Absolutely, to switch to using an OData service simply initialize Breeze with the correct adapter. For OData this would look like:
breeze.config.initializeAdapterInstance("dataService", "OData");
Make sure you make this call before creating your first EntityManager and remember to use an OData uri as the service name.
This provides full OData query support. OData saves have not yet been implemented although they are on the near term roadmap. If you really need OData save functionality, you might want to vote for it on our Breeze User Voice https://breezejs.uservoice.com/forums/173093-breeze-feature-suggestions. We take that venue seriously in making decisions about what to do next.
I'm aware of the Chris Fulstow project log4net.signalr, it is a great idea if you want a non production log since it logs all messages from all requests. I would like to have something that discriminates log messages by the request originating them and sed back to the proper browser.
Here what I've done in the appender:
public class SignalRHubAppender:AppenderSkeleton
{
protected override void Append(log4net.Core.LoggingEvent loggingEvent)
{
if (HttpContext.Current != null)
{
var cookie = HttpContext.Current.Request.Cookies["log-id"];
if (null != cookie)
{
var formattedEvent = RenderLoggingEvent(loggingEvent);
var context = GlobalHost.ConnectionManager.GetHubContext<Log4NetHub>();
context.Clients[cookie.Value].onLog(new { Message = formattedEvent, Event = loggingEvent });
}
}
}
}
I'm trying to attach the session id to a cookie, but this does not work on the same machine because the cookie is overwritten.
here is the code I use on the client to attach the event:
//start hubs
$.connection.hub.start()
.done(function () {
console.log("hub subsystem running...");
console.log("hub connection id=" + $.connection.hub.id);
$.cookie("log-id", $.connection.hub.id);
log4netHub.listen();
});
As a result, just the last page connected shows the log messages. I would like to know if there is some strategies to have the current connection id from the browser which originate the current request, if there is any.
Also I'm interested to know if there is better design to achieve a per browser logging.
EDIT
I could made a convention name based cookie ( like log-id-someguid ), but I wonder if there is something smarter.
BOUNTY
I decided to start a bounty on that question, and I would additionally ask about the architecture, in order to see if my strategy makes sense or not.
My doubt is, I'm using the hub in a single "direction" from server to client, and I use it to log activities not originating from calls to the hub, but from other requests ( potentially requests raised on other hubs ), is that a correct approach, having as a goal a browser visible log4net appender?
The idea about how to correctly target the right browser instance/tab, even when multiple tabs are open on the same SPA, is to differentiate them through the Url. One possible way to implement that is to redirect them at the first access from http://foo.com to http://foo.com/hhd83hd8hd8dh3, randomly generated each time. That url rewriting could be done in other ways too, but it's just a way to illustrate the problem. This way the appender will be able to inspect the originating Url, and from the Url through some mapping you keep server side you can identify the right SignalR ConnectionId. The implementation details may vary, but the basic idea is this one. Tracking some more info available in the HttpContext since the first connection you could also put in place additional strategies in order to prevent any hijacking.
About your architecture, I can tell you that this is exactly the way I used it in ElmahR. I have messages originating from outside the notification hub (errors posted from other web apps), and I do a broadcast to all clients connected to that hub (and subscribing certain groups): it works fine.
I'm not an authoritative source, but I also guess that such an architecture is ok, even with multiple hubs, because hubs at the end of the day are just an abstraction over a (one) persistent connection which allows you to group messaging by contexts. Behind the scenes (I'm simplifying) you have just a persistent connection with messages going back and forth, so whatever hub structure you define on top of it (which is there just to help you organizing things) you still insist on that connection, so you cannot do any harm.
SignalR is good on doing 2 things: massive broadcast (Clients), and one-to-one communication (Caller). As long as you do not try to do weird things like building keeping server-side references to specific callers, you should be ok, whatever number of Hubs, and interactions among them, you have.
These are my conclusions, coming from the field. Maybe you can twit #dfowler about this question and see if he has (much) more authoritative guidelines.
I am new to Exhange Server2007 programming. My scenario is to read mails from more than one user account at a time. Now I am reading information of one user but not for the second user at same time. Can an anybody help me to get this. I am assuming that how I can close the service for a specific user and continue for the other user with the same service.
It's a deadline situation. Immediate response can be greately helped.
Thanks in advance.
Assuming you are using the Exchange Web Services or EWS Managed API, you don't need to close anything.
Given the appropiate permissions (this is what you really need), just open the other users mailbox by specifying the users primary email address in the Bind operation:
var folder = Folder.Bind(service, new FolderId(WellKnownFolderName.Inbox, new Mailbox("someone#company.local")));