I upgraded to .NET 4.5, now SignalR seems insistent on using WebSockets in Firefox/Chrome - even though I'm only on Windows 7 which doesn't have a WebSocket Server.
The request obviously fails:
Firefox can't establish a connection to the server at ws://www.site.local/signalr?connectionData=
How do I force SignalR to forget about Websockets and use Long Polling, or is there a way of setting up Websockets for Windows 7 that I'm missing?
Update.... I'm using SignalR 0.4:
<package id="SignalR" version="0.4.0" />
<package id="SignalR.Hosting.AspNet" version="0.4.0.0" />
<package id="SignalR.Js" version="0.4.0.1" />
<package id="SignalR.Server" version="0.4.0.0" />
<package id="SignalR.StructureMap" version="0.4.1" />
I found the answer here:
https://github.com/SignalR/SignalR/wiki/SignalR-JS-Client
Basically:
$.connection.hubs.start({ transport: 'longPolling' }, function() {
console.log('connection started!');
});
In order to disable a transport on the server side, you must use something like this:
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Transports;
using Owin;
namespace MyApplication
{
public static class Startup
{
public static void ConfigureSignalR(IAppBuilder app)
{
// If using the global dependency resolver
TurnOfForeverFrame(GlobalHost.DependencyResolver);
app.MapSignalR();
}
public static void TurnOfForeverFrame(IDependencyResolver resolver)
{
var transportManager = resolver.Resolve<ITransportManager>() as TransportManager;
transportManager.Remove("foreverFrame");
}
}
}
The #reach4thelasers' solution only disable it in the client, but the client could re-enable the transport and connect.
Cheers.
For anyone looking how to disable it on the server using asp.net core 3.1:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chathub", options =>
{
options.Transports =
HttpTransportType.WebSockets |
HttpTransportType.LongPolling;
});
});
}
source: https://learn.microsoft.com/en-us/aspnet/core/signalr/configuration?view=aspnetcore-3.1&tabs=dotnet#advanced-http-configuration-options-1
Related
I have a .net core console application I am going to deploy as an Azure web job. The purpose of the job is to listen for new messages in an Azure Service Bus Queue. I have set the listener up using a function containing the [ServiceBusTrigger] Attribute. I built a dummy implementation which just reads the latest message from the queue - this works without issue - the message is passed correctly from the service bus queue to my function.
When I try to go to the next level and add an interface parameter to the function to be injected by DI I get an error.
Microsoft.Azure.WebJobs.Host.Indexers.FunctionIndexingException:
'Error indexing method 'Functions.ProcessMeasurementData''
InvalidOperationException: Cannot bind parameter 'service' to type
IProcessMeasurementService. Make sure the parameter Type is supported
by the binding. If you're using binding extensions (e.g. Azure
Storage, ServiceBus, Timers, etc.) make sure you've called the
registration method for the extension(s) in your startup code (e.g.
builder.AddAzureStorage(), builder.AddServiceBus(),
builder.AddTimers(), etc.).
This is my function. If I remove the parameter IProcessMeasurementService service it works with no issue running locally from Visual Studio 2019 (I haven't tried deploying to azure yet as a webjob), picking up new items as they are added to the Azure Service Bus Queue.
public class Functions
{
public static async Task ProcessMeasurementData(
[ServiceBusTrigger("process-measurement-data-queue", Connection = "AzureWebJobsServiceBus")] Message message,
IProcessMeasurementService service)
{
try
{
var measurements = JsonConvert
.DeserializeObject<List<CreateMeasurementInput>>
(Encoding.UTF8.GetString(message.Body));
await service.DoStuff(measurements);
// log.LogInformation(message.ContentType);
}
catch (Exception e)
{
throw;
}
}
I think I am registering the service correctly, like this:
{
// Register application services
services.AddSingleton<IProcessMeasurementService, ProcessMeasurementService>();
});
This is my main function in its entirety.
static void Main(string[] args)
{
var builder = new HostBuilder();
builder.ConfigureAppConfiguration((builder) =>
{
builder
.AddJsonFile("appsettings.json", false, true)
.AddEnvironmentVariables();
});
builder.ConfigureWebJobs(b =>
{
b.AddServiceBus(x =>
{
x.MessageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler)
{
AutoComplete = false
};
});
b.AddAzureStorageCoreServices();
});
builder.ConfigureServices(services =>
{
services.AddOptions();
// Register application services
services.AddSingleton<IProcessMeasurementService, ProcessMeasurementService>();
});
var host = builder.Build();
using (host)
{
host.Run();
}
}
From googling it feels like the problem might be something to do with my nuget package version. I tried adding a file called "host.json" in case it was a known problem with azure function versions conflicting with extensions libraries. But it did nothing. I am not actually using AzureFunctions (serverless functions I mean) but I am clutching at straws at this stage.
Does anyone know what the problem is?
This is the host.json just in case this is the issue.
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
Here're my nuget versions installed
<PackageReference Include="Microsoft.Azure.ServiceBus" Version="4.1.2" />
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.16" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="4.1.1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Sources" Version="3.0.16" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
Change from static function method to an instance member and inject the service via constructor injection directly into the function class.
public class Functions {
private readonly IProcessMeasurementService service;
public Functions (IProcessMeasurementService service) {
this.service = service;
}
public async Task ProcessMeasurementData(
[ServiceBusTrigger("process-measurement-data-queue", Connection = "AzureWebJobsServiceBus")] Message message)
{
try {
var measurements = JsonConvert
.DeserializeObject<List<CreateMeasurementInput>>
(Encoding.UTF8.GetString(message.Body));
await service.DoStuff(measurements);
// log.LogInformation(message.ContentType);
} catch (Exception e) {
//...
throw;
}
}
}
I created an ASP.Net CORE web API project, with a single controller, and would now like to call it from a client (React) web app.
However, the call fails with "No 'Access-Control-Allow-Origin' header is present on the requested resource.".
When calling the same endpoint from Fiddler, the expected response headers are not present.
Thanks to ATerry, I have further insight: the headers are not present, because the React web app and the .Net Core web API are hosted on the same box. React populates the request Origin: header which is the same as the (API) box, thus the server (being really clever about it) does not add the Allow-... response headers. However, the React app rejects the response, because of the lack of those headers.
I'm using .Net Core v2.1 (latest as of this writing).
I built the code based on
https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1
I checked these
https://weblog.west-wind.com/posts/2016/Sep/26/ASPNET-Core-and-CORS-Gotchas
CORS in .NET Core
How to enable CORS in ASP.NET Core
... but none of the suggestions worked.
Any ideas?
This is how I configure the .Net Core app (code changed from actual to try and allow anything):
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Enable CORS (Cross Origin Requests) so that the React app on a different URL can access it
// See https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1
services.AddCors(options =>
{
options.AddPolicy(Global.CORS_ALLOW_ALL_POLICY_NAME, builder => builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
});
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseCors(Global.CORS_ALLOW_ALL_POLICY_NAME);
app.UseHttpsRedirection();
app.UseMvc();
}
}
Having failed with just the above, I added the CORS attributes to the controller class and controller methods too:
[Route("api/[controller]")]
[ApiController]
[EnableCors(Global.CORS_ALLOW_ALL_POLICY_NAME)]
public class DealsController : ControllerBase
{
[...]
[HttpGet]
[EnableCors(Global.CORS_ALLOW_ALL_POLICY_NAME)]
public ActionResult<List<Deal>> GetAll()
{
return Store;
}
}
The response headers I get:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-Powered-By: ASP.NET
Date: Thu, 06 Sep 2018 12:23:27 GMT
The missing headers are:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:3000
I believe it should work fine with LOCALHOST hosting as well, just do below changes and remove and any extra changes/configurations.
Replace this:
// Enable CORS (Cross Origin Requests) so that the React app on a different URL can access it
// See https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1
services.AddCors(options =>
{
options.AddPolicy(Global.CORS_ALLOW_ALL_POLICY_NAME, builder => builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
});
with this:
services.AddCors();
and Replace this:
app.UseCors(Global.CORS_ALLOW_ALL_POLICY_NAME);
with this:
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
NOTE:
Even if your Web Api and React app are configured on LOCALHOST doesn't mean they are from same origin, it is because they are hosted on different port like react app is hosted on LOCALHOST:3000 and Web Api is hosted on LOCALHOST:5000. Web api will complaint if client(react app) is requesting from different port.
Above Web Api code will allow ANY ORIGIN and in production applications this is not safe so you need to allow specific ORIGIN to CORS access.
Managed to solve it by changing the URL used to access the server from a localhost based one to an IP address based one (localhost/api to 192.168.1.96/api).
It seems that part of the filtering that ATerry mentioned is based on host name: IIS doesn't send the Allow-... headers if hostname is localhost. Trouble is that React requires them.
You could try something like below as explained here: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder => builder.WithOrigins("http://example.com"));
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Shows UseCors with named policy.
app.UseCors("AllowSpecificOrigin");
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
In your scenario it could be changed to something like the code below.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy(Global.CORS_ALLOW_ALL_POLICY_NAME,
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
}));
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseCors(Global.CORS_ALLOW_ALL_POLICY_NAME);
app.UseHttpsRedirection();
app.UseMvc();
}
}
This code might not look any different from yours however, there is a slight difference in the way the actions(what you call the builder) are defined. I hope that helps, good luck! :)
I got stuck with this same issue recently but doubted if mine was CORS related. So I went to deploy the app to my local IIS to check if that will get resolved somehow. Then checked the logs and found an issue pertaining to circular reference in data models - "Self referencing loop detected for property..". Applied an action in Startup.js to resolve the issue like so,
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options =>
{
options.SerializerSettings.Formatting = Formatting.Indented;
// this line
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
I am looking for a template to use asp.net core 2.0 with angular 6 in one solution with f5 hit to run the application.
Can you help find such request ?
Thanks
tutorial
here:
I would not use
Microsoft.DotNet.Web.Spa.ProjectTemplates::2.0.0-rc1-final
but
Microsoft.DotNet.Web.Spa.ProjectTemplates::2.0.0
You can use Angular6.
The magic is that .net core starts new command line itself and runs npm script.
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
npm start is by default alias for ng serve.
I do have working project with Angular6 and Core 2.
My project.csproj
...
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.0.0" />
</ItemGroup>
...
and Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.SpaServices.AngularCli;
namespace AngularSPA
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
}
}
But I only have aesthetic problem with built-in command line, you can see my question here.
I created one, it is on GitHub, it could be a good starting point but it is not perfect, it should grow and evolve during next months...
https://github.com/JuanGarciaCarmona/AspNetCore21Ang6Template
Also there is an article in Code Project that explains how to use it.
https://www.codeproject.com/Articles/1246748/Angular-within-ASP-NET-Core
I hope it helps.
I am developing a real time application based on signal R . I am using .NET framework 4 , Signal R version 1.2.2 in VS 2010.I am getting a Hub reference error stating
Uncaught Error: SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/hubs'></script>.
I got a solution to add the Hub reference in global file. But since i am using DNN framework it contains multiple projects and have a common global file.
RouteTable.Routes.MapHubs("/myhubs", new HubConfiguration());
i tried adding this piece of code there, but it too didn't works..
my hub class
public class ChatHub : Hub
{
public void Send(string message)
{
Clients.Others.receive(message);
}
}
And start up class is
[assembly: OwinStartup(typeof(DotNetNuke.Modules.VideoChat.Startup))]
namespace DotNetNuke.Modules.VideoChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapHubs();
}
}
}
i am using jquery on client side.
var chat = $.connection.chatHub;
$.connection.hub.start().done(function () {}
Can anyone suggest a way around
You need to follow these steps:
Create a Hub class on the server that inherits the Hub class from SignalR
Create client proxy for the Hub class (using .NET class or javascript code)
Startup the Hub on the server using MapHubs() (obsolete)
Your question does not give enought information. Is it a web application? Are you using javascript or .NET on the client side?
See this post: SignalR hubclass in classlibrary
EDIT
Here is what you should have in your Startup class now that I see that you are using OWIN:
[assembly: OwinStartup("StartupConfiguration", typeof(DotNetNuke.Modules.VideoChat.Startup))]
namespace DotNetNuke.Modules.VideoChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// SignalR Hub Startup
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = true;
hubConfiguration.EnableJSONP = false;
app.MapSignalR(hubConfiguration);
}
}
}
In your web.config, add these lines:
<appSettings>
<add key="owin:appStartup" value="StartupConfiguration" />
<add key="owin:AutomaticAppStartup " value="true" />
</appSettings>
I have a simple SingulaR example that I've added to a legacy ASP.Net MVC application.
Here are the various parts:
OWIN Startup class
[assembly: OwinStartup(typeof (Startup))]
namespace MyApp.Web
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
SignalR Hub
using System.Collections.Generic;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
namespace MyApp.Web
{
[HubName("podService")]
public class PodServiceHub : Hub
{
public PodServiceHub()
{
;
}
public IEnumerable<string> GetMessages()
{
return new[] {"blah", "blah", "blah"};
}
}
}
Server-side facade
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
namespace MyApp.Web
{
public class PodService
{
PodService(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
}
public PodService()
: this(GlobalHost.ConnectionManager.GetHubContext<PodServiceHub>().Clients)
{
}
IHubConnectionContext<dynamic> Clients { get; set; }
public void SendMessageToClient(string message)
{
Clients.All.doSomething(message);
}
}
}
Portions of startup Javascript:
var podService = $.connection.podService;
...
$.extend(podService.client, {
doSomething: function(message) {
console.log("received message:" + message);
}
});
// test
$.connection.hub.start()
.done(function() {
podService.server.getMessages()
.done(function(messages) {
console.log("received message:" + message);
});
});
Within one of the controllers called by the first page:
_podService.SendMessageToClient("Hello from the server!");
Upon executing the application, the following error is displayed in the console of Chrome's dev tools:
WebSocket connection to 'ws://localhost:62025/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=02LJFqBcRBWKXAOlaSwgMPWG0epV7AFl19gNjFCvA0dxD2QH8%2BC9V028Ehu8fYAFN%2FthPv65JZKfK2MgCEdihCJ0A2dMyENOcdPkhDzEwNB2WQ1X4QXe1fiZAyMbkZ1b&connectionData=%5B%7B%22name%22%3A%22podservice%22%7D%5D&tid=6' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET
After this error, however, the podService.server.getMessages() returns with the message from the server printing ["blah", "blah", "blah"] to the console and subsequently the doSomething client function is invoked printing "received message: Hello from the server!".
The calls from both the client and the server are transmitting data, so this error doesn't appear to be breaking the app. It definitely seems to be an issue though. The code above was based upon the sample code generated by the Microsoft.AspNet.SignalR.Sample NuGet package which doesn't display the same behavior. The only difference I'm aware of between my example and NuGet-based sample is that I've added this to a legacy MVC app vs. a pure OWIN-based app. Based upon a comment I read on this SO question this shouldn't be an issue.
So, what's wrong with this example usage and/or what could be causing the connection reset?
I made sure:
the web socket component is enabled in IIS
and the "allowKeepAlive" setting is not set to false in my web.config
But in my case the problem was caused by a packages version mismatch:
In the packages.config Microsoft.Owin.Host.SystemWeb version 2.1.0 was referenced accidentally
<package id="Microsoft.Owin.Host.SystemWeb" version="2.1.0" targetFramework="net452" />
While all the other Owin related packages were referencing version 3.0.1
I updated Microsoft.Owin.Host.SystemWeb to version 3.0.1
Then I had to make sure in the web.config file the "httpRuntime" element targeted the framework version 4.5
<system.web>
<httpRuntime targetFramework="4.5" />
</system.web>
The two steps above solved the problem.
Just ran in to this one myself. In my case the answer seems to be enabling WebSockets for IIS.
Enable WebSockets in IIS 8.0
It works because signalR falls back to one of the following depending on the capabilities of the browser and server.
Server Sent Events.
Forever Frame
AJAX Long Polling
For more information on the transports used and their fallbacks see here
In my case, I had to remove
<httpProtocol allowKeepAlive="false" />
from our web.config (it was there for historical reasons).
In my Case I was using
string sqlConnectionString = ConfigurationManager.ConnectionStrings["GAFI_SignalR"].ConnectionString;
GlobalHost.DependencyResolver.UseSqlServer(sqlConnectionString);
The problem was accessing the database when the user didin't have permission to connect to the database.