I have set up a signalR website .net core. My function in my hub is:
public async Task Notify(int id) {
await Clients.All.InvokeAsync("Notified", id);
}
I have also tested this with the following js:
let connection = new signalR.HubConnection(myURL);
connection.on('Notified', data => {
console.log(4, data);
});
connection.start();
The js code seems to work fine and I see the log when I try connection.Invoke('Notify').
Now I have a console app that can needs to make the invoke. I am trying this in two ways and don't mind either solution:
1. A mvc controller within the signalR website that can take the id and invoke 'Notified'.
2. Use the client library Microsoft.AspNetCore.SignalR.Client in the console app.
The way 1 I have only done in classic asp.net like this:
GlobalHost.ConnectionManager.GetHubContext(hubName)
But couldn't find a way to do this in .net core.
Way 2 I have used the library and tried this so far:
var con = new HubConnectionBuilder();
con.WithUrl(myURL);
var connection = con.Build();
connection.InvokeAsync("Notify",args[0]).Wait();
This is the closest I have come to create a connection in the same way as the js code. However this code throws a null pointer when calling connection.InvokeAsync. The connection object is not null. It seems to be an internal object that is null. According to the stack trace the exception is thrown when a MoveNext() function is internally called.
Well looks like both are not currently possible. As of now I just used a forced way which is hopefully temporary.
I have created and used the following base class for hubs:
public abstract class MyHub : Hub
{
private static Dictionary<string, IHubClients> _clients = new Dictionary<string, IHubClients>();
public override Task OnConnectedAsync()
{
var c = base.OnConnectedAsync();
_clients.Remove(Name);
_clients.Add(Name, Clients);
return c;
}
public static IHubClients GetClients(string Name) {
return _clients.GetValueOrDefault(Name);
}
}
GlobalHost is gone. You need to inject IHubContext<THub> like in this sample.
This can be a bug in SignalR alpha1. Can you file an issue on https://github.com/aspnet/signalr and include a simplified repro?
Related
I am looking for a way to subscribe to events like Storing a specific object type to ServiceStack.Redis.
For example I may
using (var redisClient = new RedisClient())
using (var redisMyObjects = redisClient.As<MyObject>())
{
redisMyObjects.Store(myObject);//<-- I want this to trigger an event somehow
}
Is there anything like a OnStore event which I can hook too, anything out of the box? if not, is there any recommendation about how this should be done?
I don't think there is anything you can hook into (could be wrong).
Two options that came to mind:
1 - Make an extension method
2 - Publish a message to store your object and have a handler that listens for a response and does something. This is probably overkill since it's heading into the publish/subscribe realm. But, I think, worth looking into. (Basic example here and see Pub/Sub here).
Extension Method
public static class RedisClientExtensions
{
public static void StoreWithTrigger<T>(this IRedisTypedClient<T> redisClient, T value, Action<T> trigger)
{
redisClient.Store(value);
trigger(value);
}
}
Using ExtensionMethod
public void MyMethod()
{
using (var redisClient = new RedisClient())
using (var redisMyObjects = redisClient.As<MyObject>())
{
redisMyObjects.StoreWithTrigger<MyObject>(new MyObject(), TriggerEvent);//<-- I want this to trigger an event somehow
}
}
private void TriggerEvent<T>(T value)
{
//dosomething
}
Hope this gives you some ideas.
How do I fetch the Measurement System setting value in javascript?
I'm guessing that it would be throw some WinJS call.
The logical place would be Windows.Globalization, but not seeing if offered there. One pretty simple workaround - faster to write than to research the setting :) is to create a Windows Runtime Component in C# that calls in to System.Globalization:
namespace WindowsRuntimeComponent
{
public sealed class RegionalSettings
{
public bool isMetric()
{
return System.Globalization.RegionInfo.CurrentRegion.IsMetric;
}
}
}
Then add as a reference to your JavaScript app and invoke there:
var r = new WindowsRuntimeComponent.RegionalSettings;
var isMetric = r.isMetric();
I have WebAPI implementation with method like this:
public IEnumerable<Device> GetAllDevices()
public Device GetDeviceById(int id)
Looks ok, it works when running in IIS or selfhosted. Returns JSON objects correctly.
However first method fails in my unit test where I attempt to use inmemory server.
System.InvalidOperationException : Cannot create and populate list type System.Linq.IQueryable`1[Test.Device].
This goes down to Newtonsoft.Json.Serialization assembly. An example of the test follow:
[Test]
public void GET_AskingForListOfDevices_GettingOk200WithListOfDevicesInJSON()
{
var client = new HttpClient(InMemoryServer);
HttpRequestMessage request = CreateRequest("api/devices", "application/json", HttpMethod.Get);
using (HttpResponseMessage response = client.SendAsync(request).Result)
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
Assert.NotNull(response.Content);
Assert.AreEqual("application/json", response.Content.Headers.ContentType.MediaType);
// next line throws exc
var content = response.Content.ReadAsAsync<IQueryable<Device>>().Result;
Assert.AreEqual(3, content.Count());
}
request.Dispose();
}
Any idea where to look?
UPDATE
The example below throws that error, however I found the solution to avoid it. Just by using IList<> instead of IQueryable<>. Still It does not answer me the question why it's working in Fiddler. Does it use the same trick?
I am running into same situation. IQueryable throws exception but if you use IEnumerable then it works.
I am new to SignalR and trying to implement long running result pooling. I have added JS to my ASP.NET MVC app and created bug class.
JS
<script type="text/javascript">
var message= $.connection.messageHub;
$(function () {
message.addMessage = function (htmlstring) {
alert(htmlstring);
};
$.connection.hub.start(function () {
message.longRunningMethod('#HttpContext.Current.Session.SessionID');
});
});
</script>
c# code
[HubName("messageHub")]
public class MessagesHub : Hub
{
public void longRunningMethod(string sessionId)
{
var repeatChecking = 0;
while (repeatChecking < 3000000)
{
Caller.addMessage("Test");
repeatChecking++;
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
}
The code works fine but there is one problem. Every time the same user refresh web page new Hub class is created and new longRunningMethod method is executed. I would like to resume connection and attach to the same hub instance and resume receiving messages. Could anyone explain how to implement this?
Hubs are created and destroyed very frequently so never put any data that you expect to last on them (unless it's static).
I'm not quite sure why you're looking to have a long running method that can take in data (because SignalR is always up and available to take in/handle data) but here's how you can do it:
Checkout the SignalR stock ticker example (you can pull it in via Nuget). It creates a single instance class that fires up a timer. That timer is used to broadcast data down to the clients. https://github.com/SignalR/SignalR-StockTicker
You can also check out ShootR. It's a multiplayer game built with SignalR that does much of the same. Creates a background timer that acts as the game loop on the server and then pushes data down to clients. https://github.com/NTaylorMullen/ShootR
Ultimately your solution will involve either making a singleton or a static timer that acts as your "long" running method.
Hope this helps!
We're looking at using an AOP framework for handling things like logging, tracing, and exception handling. I've built a prototype using PostSharp and now I'm trying to build the same functionality using AspectMap.
In a nutshell, I have an ASP.NET MVC 3 application and I want an aspect that I can easily attach to my controller methods that shows the entry, exit, execution time, and argument values. My PoC is the basic MVC 3 Internet Application template (File > New > Project > Web > ASP.NET MVC 3 Web Application > Internet). What I've done so far...
Created an AspectsRegistry
public class PoCRegistry : AspectsRegistry
{
public PoCRegistry()
{
ForAspect<ProfileAttribute>().HandleWith<ProfileHandler>();
}
}
Created a StructureMapControllerFactory
public class StuctureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance( RequestContext requestContext, Type controllerType )
{
if( controllerType == null ) return null;
try
{
return ObjectFactory.GetInstance( controllerType ) as Controller;
}
catch( StructureMapException )
{
Debug.WriteLine( ObjectFactory.WhatDoIHave() );
throw;
}
}
}
Registered everything in Application_Start
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters( GlobalFilters.Filters );
RegisterRoutes( RouteTable.Routes );
ObjectFactory.Initialize( ie => ie.AddRegistry( new PoCRegistry() ) );
ControllerBuilder.Current.SetControllerFactory( new StuctureMapControllerFactory() );
}
At this point the application works, and I can see it's using my StructureMapControllerFactory to build the controller (debugger steps into that code). The problem is that I can't figure out where or how to "enrich" the controller that is generated. In the tutorial it says I need to use something like the following:
For<ICaseController>()
.Use<CaseController>()
.EnrichWith( AddAspectsTo<CaseController> );
But in the tutorial that goes in the AspectRegistry, which doesn't seem like the right place in this situation because the registry isn't responsible for resolving the controller request, the controller factory is. Unfortunately the GetInstance() method in the controller factory returns an object and the EnrichWith() method needs a SmartInstance.
At this point I'm stuck. Any hints, pointers, or assistance would be appreciated.
This is a use case I hadn't thought about to be honest. I'll setup a test project today and see what I can come up with. Bear with me!
Update
I've been playing around with the backend code (you can get a complete copy of the code from http://aspectmap.codeplex.com) and the relevant part is this:
public T AddAspectsTo<T>(T concreteObject)
{
ProxyGenerator dynamicProxy = new ProxyGenerator();
return (T)dynamicProxy.CreateInterfaceProxyWithTargetInterface(typeof(T), concreteObject,
new[] { (IInterceptor)new AspectInterceptor(attributeMap) });
}
This is using the castle dynamic proxy stuff. Unfortunately the CreateInterfaceProxy... methods require that an interface is passed in (rather than a base class like I'd hoped). Now I've found this question:
C# Dynamic Proxy 2 generate proxy from class with code in constructor ? How to?
That seems to show that it could be possible to use CreateClassProxy. I've not had chance to try this out yet and I'm going away for a week away from the computer. If you want to try and wire it up though you're welcome to get the source from codeplex and give it a try though. If not I'll put something together when I return.
Action filters can be used to provide such AOP functionality.
http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs
http://msdn.microsoft.com/en-us/library/dd410056%28v=vs.90%29.aspx