Signalr: Client in asp.net mvc connect to external server - c#

I need to connect my web application on a server SignalR. This server is being accessed by a Windows Phone application and works as it should. What I need to do is access via the Web application and send a message to this phone windows application that is connected on the other side.
I want to communication via Controller for there must notify anything on the web site screen for the user.
Server Startup.cs:
internal class Startup
{
public void Configuration(IAppBuilder app)
{
try
{
app.UseCors(CorsOptions.AllowAll);
ConfigureGlobalHost();
var configuration = new HubConfiguration
{
EnableDetailedErrors = true,
EnableJSONP = true
};
app.MapSignalR("/signalr", configuration);
}
catch (Exception)
{
//Log.AddMessage("An error occurred during server configuration: " + ex.Message);
}
}
public void ConfigureGlobalHost()
{
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromMinutes(1);
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromMinutes(1);
GlobalHost.Configuration.TransportConnectTimeout = TimeSpan.FromMinutes(10);
GlobalHost.Configuration.DefaultMessageBufferSize = 500;
}
}
ConnectionHelper:
public class HubConnectionHelper : IDisposable
{
public IHubProxy HubProxy { get; set; }
public HubConnection Connection { get; set; }
private string _serverURI;
public HubConnectionHelper(string nomeDoHub, string urlServicoCentral)
{
_serverURI = string.Format("http://{0}:8080", urlServicoCentral.Split(':')[0]);
Connection = new HubConnection(_serverURI);
Connection.TransportConnectTimeout = TimeSpan.FromMinutes(10);
Connection.Closed += Connection_Closed;
HubProxy = Connection.CreateHubProxy(nomeDoHub);
}
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(ConfiguracaoTerminalViewModel cTerminal)
{
if (ModelState.IsValid)
{
var loja = _lService.ObterLoja();
if (_cTerminalService.Gravar(new ConfiguracaoTerminal
{
Id = Guid.NewGuid(),
CaminhoServidorEmissao = cTerminal.CaminhoServidorEmissao,
NumeroEletronico = cTerminal.NumeroEletronico,
Serie = cTerminal.Serie,
LojaId = cTerminal.LojaId,
TerminalId = cTerminal.TerminalId,
AmbienteNFe = cTerminal.AmbienteNFe
}))
{
await _cTerminalHub.NotificarTerminal(cTerminal.TerminalId.ToString(),
"Configuração inserida com sucesso.\n\nFim das configurações.");
return RedirectToAction("Index");
}
}
return View(cTerminal);
}
Server hub:
public class ConfiguracaoTerminalHub : Hub, IDisposable
{
private readonly SignalRConnectionService _signalRConnectionService;
private readonly TerminalService _terminalService;
public ConfiguracaoTerminalHub()
{
_signalRConnectionService = new SignalRConnectionService();
_terminalService = new TerminalService();
}
public void NotificarTerminal(string connectionId, string message)
{
Clients.Client(connectionId.ToString()).ReceberNotificacaoConfiguracaoTerminal(message);
Console.WriteLine("Notificação enviada do Retaguarda para um terminal pendente.");
}
public override Task OnConnected()
{
SalvarConexao(Guid.Parse(Context.Headers.Get("terminalId")));
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
ExcluirConexao(Guid.Parse(Context.ConnectionId));
return base.OnDisconnected(stopCalled);
}
EDIT:
ConfiguracaoTerminalHub (clientside, use for connect):
public class ConfiguracaoTerminalHub : IDisposable
{
public ConfiguracaoTerminalHub(string urlServidor)
{
_conHelper = new HubConnectionHelper("ConfiguracaoTerminalHub", urlServidor);
}
public async Task NotificarTerminal(string connectionId, string message)
{
await _conHelper.Connection.Start(); //the error occurs here
await _conHelper.HubProxy.Invoke("NotificarTerminal", connectionId, message);
}
}
Error:
StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1,
Content: System.Net.Http.StreamContent, Headers:
{
Date: Tue, 12 Jan 2016 12:57:51 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 0
}

Related

Write integration test for grpc service

I use this repository to write an ASP.NET Core gRPC integration test. But if I have a service method that this call another gRPC service, I get an error that means the second service is not available.
My method code is something like this:
public async Task<GetPersonReply> GetPersonInfoAsync(GetPersonRequest request, CallContext context = default)
{
HttpContext httpContext = context.ServerCallContext.GetHttpContext();
LanguageExt.Option<string> userDisplayName = httpContext.User.Identity.Name;
GrpcChannel channel = Toolkit.ChannelFactory.CreateChannelWithCredentials("https://localhost:5201");
IAddressService client = channel.CreateGrpcService<IAddressService>();
GetAddressReply serviceReply = await client.GetAddressAsync(
new GetAddressRequest { Street = "test setree", ZipCode = "428" });
return new GetPersonReply
{
DisplayName = userDisplayName.Some(x => x).None(string.Empty),
Address = serviceReply.Address
};
}
My fixture class:
namespace IntegrationTests.Fixture
{
public sealed class TestServerFixture : IDisposable
{
private readonly WebApplicationFactory<Startup> _serverFactory;
private readonly WebApplicationFactory<SecondServer.Startup> _secondServerFactory;
public TestServerFixture()
{
_serverFactory = new WebApplicationFactory<Startup>();
_secondServerFactory = new WebApplicationFactory<SecondServer.Startup>();
HttpClient serverClient = _serverFactory.CreateDefaultClient(new ResponseVersionHandler());
HttpClient secondServerClient = _secondServerFactory.CreateDefaultClient(new ResponseVersionHandler());
ServerGrpcChannel = Toolkit.ChannelFactory.CreateChannelWithCredentials(
Contracts.GrpcUrlConstants.SERVER_GRPC_URL,
serverClient);
SecondServerGrpcChannel = Toolkit.ChannelFactory.CreateChannelWithCredentials(
Contracts.GrpcUrlConstants.SECOND_SERVER_GRPC_URL,
serverTestClient);
}
public GrpcChannel ServerGrpcChannel { get; }
public GrpcChannel SecondServerGrpcChannel { get; }
public void Dispose()
{
_serverFactory.Dispose();
_serverTestFactory.Dispose();
}
private class ResponseVersionHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Version = request.Version;
return response;
}
}
}
}
And my test code :
namespace IntegrationTests
{
[Collection(TestCollections.ApiIntegration)]
public class PersonServiceAcceptanceTests
{
public PersonServiceAcceptanceTests(TestServerFixture testServerFixture)
{
GrpcChannel serverChannel = testServerFixture.ServerGrpcChannel;
GrpcChannel secondServerChannel = testServerFixture.TestServerGrpcChannel;
_clientPersonService = serverChannel.CreateGrpcService<IPersonService>();
_clientAddressService = testServerChannel.CreateGrpcService<IAddressService>();
}
private readonly IPersonService _clientPersonService;
private readonly IAddressService _clientAddressService;
[Theory]
[InlineData("test1", "987")]
[InlineData("test2", "123")]
public async Task GetAddressService_ShouludCall_Success(string street, string zipCode) --> this test pass successfully
{
GetAddressRequest request = new GetAddressRequest { Street = street, ZipCode = zipCode };
GetAddressReply result = await _clientAddressService.GetAddressAsync(request, CallContext.Default);
result.Should().NotBeNull();
result.Address.Should().NotBeNullOrWhiteSpace();
result.Address.Should().Contain(street);
result.Address.Should().Contain(zipCode);
}
[Fact]
public async Task GetPersonInfo_Should_Success() //My Issue -> this test has error and not pass
{
GetPersonRequest request = new GetPersonRequest { PersonId = "101" };
GetPersonReply result = await _clientPersonService.GetPersonInfoAsync(request, CallContext.Default);
result.Should().NotBeNull();
}
}
}
Is there anyone tell me how can I write an integration test containing two separate services that one call in another?

SignalR remote client

I want to connect to signalr with a client thats on a different pc. This means i wont be using localhost. I already made a simple networkdiscovery to get the correct ip address but it seems signalr does not allow remote clients to connect even though I already use CorsOptions.AllowAll.
class Startup
{
public void Configuration(IAppBuilder app)
{
var hubConfiguration = new HubConfiguration
{
#if DEBUG
EnableDetailedErrors = true
#else
EnableDetailedErrors = false
#endif
};
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR(hubConfiguration);
}
}
Iam using duality which is a 2d game engine. Here is the server:
public class SignalRServer : Component, ICmpInitializable
{
private IDisposable _signalRServer;
public int _port { get; set; } = 8080;
public void StopServer()
{
if (_signalRServer != null)
_signalRServer.Dispose();
}
public void OnInit(InitContext context)
{
if (context == InitContext.Activate && DualityApp.ExecContext == DualityApp.ExecutionContext.Game)
{
var networkDiscovery = new NetworkDiscovery(_port, "TestGame"); //Network discovery to get the ip adres of the server if one is found
IPEndPoint ipEndPoint;
if (networkDiscovery.LookForServer(out ipEndPoint))
{
try
{
ConnectToServer(ipEndPoint).Wait();
Debug.WriteLine($"Connection established to {ipEndPoint}");
}
catch (Exception ex)
{
Debug.WriteLine("Could not find server");
}
}
else //No server was found so we create one
{
Debug.WriteLine("Starting signalR server");
string url = $"http://*:{_port}"; //To test go to http://localhost:8080/signalr/hubs
networkDiscovery.Start();
_signalRServer = WebApp.Start<Startup>(url);
}
}
}
private async Task ConnectToServer(IPEndPoint ipEndPoint)
{
var hubConnection = new HubConnection($"http://{ipEndPoint}/");
IHubProxy hubProxy = hubConnection.CreateHubProxy(nameof(MyHub));
hubProxy.On<string, string>(nameof(MyHub.Send), (name, message) =>
{
Debug.WriteLine("Incoming data: {0} {1}", name, message);
});
ServicePointManager.DefaultConnectionLimit = 10;
await hubConnection.Start();
}
public void OnShutdown(ShutdownContext context)
{
StopServer();
}
}
And the hub:
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
public override Task OnConnected()
{
Debug.WriteLine("Client connected: " + Context.ConnectionId);
Send("Server", $"Client with id {Context.ConnectionId} has connected");
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
Debug.WriteLine("Client disconnected: " + Context.ConnectionId);
return base.OnDisconnected(stopCalled);
}
}

Connecting Silverlight client to SignalR server

I've been driving myself nuts trying to resolve this issue so really hoping someone has some insight.
I have a console application which runs/hosts my signalR server.
I have already successfully connected to it using a web(javascript) client and a windows forms client with no trouble at all.
BUT for the life of me I cannot get a silverlight client to connect to it. Initially I was getting a
'System.Security.SecurityException' occurred in Microsoft.Threading.Tasks error
on
await Connection.Start();
I managed to fix that by force sending the clientaccesspolicy file using code i found on a random thread.
THREAD
However the connection still never establishes. The status goes thru connecting, disconnected, connection closed.
I am at my wits end as to why this won't work. Any input is appreciated. Code below.
MainPage.xaml.cs
public partial class MainPage : UserControl
{
private SignalRClient client;
public MainPage()
{
InitializeComponent();
dataGrid1.ItemsSource = new ItemsCollection();
client = new SignalRClient();
client.RunAsync();
Debug.WriteLine("Init Done");
}
}
-
SignalRClient.cs
public class SignalRClient
{
private HubConnection Connection { get; set; }
private IHubProxy HubProxy { get; set; }
const string url = "http://localhost:8080/";
public SignalRClient()
{
}
public async void RunAsync()
{
Connection = new HubConnection(url, useDefaultUrl: true);
Connection.Closed += Connection_Closed;
Connection.StateChanged += ConnectionDidSomething;
HubProxy = Connection.CreateHubProxy("TickerHub");
HubProxy.On<string>("receiveAllData", data => Debug.WriteLine("RECDATA={0}", data));
try
{
await Connection.Start();
}
catch (HttpClientException e)
{
Debug.WriteLine("Unable to connect to server.1 {0}", e.Message);
return;
}
catch (HttpRequestException e)
{
Debug.WriteLine("Unable to connect to server.2 {0}", e.Message);
return;
}
}
-
Server
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:8080/";
using (WebApp.Start(url))
{
Console.WriteLine("SignalR server running on {0}", url);
Console.ReadLine();
}
Console.ReadLine();
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
Console.WriteLine("Configuration");
//Tried this approach too
/*app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});*/
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR<ClientAccessPolicyConnection>("/clientaccesspolicy.xml");
}
}
-
TickerHub.cs
public class TickerHub : Hub
{
public override Task OnConnected()
{
string connectionID = Context.ConnectionId;
Console.WriteLine("New Connection:" + connectionID);
InitNewClient(connectionID);
return base.OnConnected();
}
//send all data to newly connected client
public void InitNewClient(string connectionID)
{
}
//client requested all data
public void GetAllData()
{
Console.WriteLine("Get Data Triggered");
Clients.All.receiveAllData("TESTING123");
}
}
I figured it out! Hopefully this helps someone in the future.
Its quite simple. This is what you need to have in your startup class configuration method.
Below that is the code required to send the clientaccesspolicy.xml.
class Startup
{
public void Configuration(IAppBuilder app)
{
// Branch the pipeline here for requests that start with "/signalr"
app.Map("/signalr", map =>
{
// Setup the CORS middleware to run before SignalR.
// By default this will allow all origins. You can
// configure the set of origins and/or http verbs by
// providing a cors options with a different policy.
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
// You can enable JSONP by uncommenting line below.
// JSONP requests are insecure but some older browsers (and some
// versions of IE) require JSONP to work cross domain
EnableJSONP = true
};
// Run the SignalR pipeline. We're not using MapSignalR
// since this branch already runs under the "/signalr"
// path.
map.RunSignalR(hubConfiguration);
});
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR<ClientAccessPolicyConnection>("/clientaccesspolicy.xml");
}
}
-
public class ClientAccessPolicyConnection : PersistentConnection
{
public override Task ProcessRequest(Microsoft.AspNet.SignalR.Hosting.HostContext context)
{
string[] urlArray = context.Request.Url.ToString().Split('/');
string path = urlArray[urlArray.Length - 1];
if (path.Equals("clientaccesspolicy.xml", StringComparison.InvariantCultureIgnoreCase))
{
//Convert policy to byteArray
var array = Encoding.UTF8.GetBytes(ClientAccessPolicy);
var segment = new ArraySegment<byte>(array);
//Write response
context.Response.ContentType = "text/xml";
context.Response.Write(segment);
//Return empty task to escape from SignalR's default Connection/Transport checks.
return EmptyTask;
}
return EmptyTask;
}
private static readonly Task EmptyTask = MakeTask<object>(null);
public static Task<T> MakeTask<T>(T value)
{
var tcs = new TaskCompletionSource<T>();
tcs.SetResult(value);
return tcs.Task;
}
public static readonly string ClientAccessPolicy =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<access-policy>"
+ "<cross-domain-access>"
+ "<policy>"
+ "<allow-from http-request-headers=\"*\">"
+ "<domain uri=\"*\"/>"
+ "</allow-from>"
+ "<grant-to>"
+ "<resource path=\"/\" include-subpaths=\"true\"/>"
+ "</grant-to>"
+ "</policy>"
+ "</cross-domain-access>"
+ "</access-policy>";
}

SignalR connection to old browser drops if new browser opens

I have application in which I am showing data from sensors using SignalR. It uses ASP.net membership to authenticate the users. It all works fine if I only open one browser window(e.g. Firefox). If I open same website in another browser e.g. Chrome at the same time then signalR connection to firefox browser drops even if the user is different. This is what I am using to broadcast message:
Hub
[Authorize]
public class DataHub:Hub
{
private readonly RealTimeData _sensor;
public DataHub() : this(RealTimeData.Instance) { }
public DataHub(RealTimeData data)
{
_sensor = data;
}
public override Task OnConnected()
{
// _sensor.UserId = Context.ConnectionId; changed to
_sensor.UserId = Membership.GetUser().ProviderUserKey.ToString();
return base.OnConnected();
}
}
public class RealTimeData
{
//User Id
public String UserId { get; set; }
private readonly static Lazy<RealTimeData> _instance = new Lazy<RealTimeData>(() => new RealTimeData(GlobalHost.ConnectionManager.GetHubContext<DataHub>().Clients));// Singleton instance
private IHubConnectionContext Clients;
private void BroadcastDataOfAllSensors(List<SensorDetails> sensor)
{
//Clients.Client(UserId).updateDashboard(sensor);changed to
Clients.User(UserId).updateDashboard(sensor);
}
}
Application Startup
public class StartUp
{
public void Configuration(IAppBuilder app)
{
var idProvider = new UserIdProvider();
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);
app.MapSignalR();
}
}
UserId
public class UserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
var userId = Membership.GetUser().ProviderUserKey;
return userId.ToString();
}
}

SignalR + passing custom object from server to client not working

I am trying to pass a custom object from self hosted signalr hub server to all the clients, the method in client side not getting invoked .But if the same custom class object is passed from client to server works fine, meaning it invokes the server method.
below is the sample code :
public class ChatHub : Hub
{
public void Send(DataContract message)
{
//below call not reaching to client while passing custom obj
Clients.All.SendMessage(message);
//below string passing works - means invokes client method
Clients.All.SendMsg("test");
}
}
custom class defined in both client and server project via dll:
public class DataContract
{
public string Name
{
get;set;
}
public int Id
{
get;set;
}
}
client side method:
public class SignalRClient
{
HubConnection hubConnection = null;
IHubProxy chat;
public SignalRClient()
{
hubConnection = new HubConnection("https://localhost/");
chat = hubConnection.CreateHubProxy("ChatHub");
}
public void StartConnection()
{
if (hubConnection != null)
{
hubConnection.Start().Wait();
}
chat.On<DataContract>("SendMessage", (stock) =>
{
Console.WriteLine("name {0} id {1}", stock.Name, stock.Id.ToString());
});
chat.On<string>("SendMsg", (message) =>
{
Console.WriteLine(message);
});
}
public void SendMessage(DataContract dd)
{
dd.Name = "test";
chat.Invoke("Send", dd).Wait();
}
public void SendMessage(string msg)
{
chat.Invoke("SendMsg", "Console app", msg).Wait();
}
}
//program.cs
main()
{
SignalRClient client = new SignalRClient();
client.StartConnection();
string msg = null;
while ((msg = Console.ReadLine()) != null)
{
DataContract dd = new DataContract { Name = "arun", Id = 9 };
//below calls reaches to server both string type and custome obj
client.SendMessage(dd);
client.SendMessage("client");
}
}
Any clue on why when calling from server (i.e Clients.All.SendMessage(message); ) not invoking client method when param is custom object.
Thanks in advance.

Categories