How to add a signalr pipeline module in Azure mobile service - c#

I want to add a signalr pipeline module as described here.
The article says to add code to startup.cs file but I don't have such a class in my mobile service. Also, the code uses GlobalHost which from my (limited) experience does not really work inside a mobile service.
I tried adding this line in WebApiConfig class but it doesn't work:
GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule());

I couldn't find the answer anywhere so I dug in the mobile services signalr assembly and found the solution.
To add your own module, add the following code to WebApiConfig:
var hubPipeline = config.DependencyResolver.GetSignalRDependencyResolver().Resolve<IHubPipeline>();
hubPipeline.AddModule(new MyModule());

Related

Soap Endpoints with ASP.NET Core 6

Currently I have only worked with REST and setting my endpoints directly in the Controller.
For example:
[HttpGet("someEndpoint")]
Now I have to work with SOAP and I'm trying to set the endpoint in my Program.cs (see screenshot). I'm always getting an error for the BasicHttpBinding().
My question: do I have to set the endpoints in the controller? The same way I'm doing it with my normal REST API? I didn't find an answer for this on the Internet. Thank you very much in advance.
(My native language is German, sorry for my English :) )
EDIT: the code:
using SoapCore;
using System.ServiceModel;
using WebAPI_2023.Models;
using WebAPI_2023.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSoapCore();
builder.Services.AddScoped<CalculatorService>();
builder.Services.AddSingleton<ISampleService, SampleService>();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSoapEndpoint<ISampleService>("/Service.asmx", new
BasicHttpBinding(), SoapSerializer.XmlSerializer);
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
EDIT 2 : I found my error.Now it works perfectly :)
app.UseEndpoints(endpoints =>
{
endpoints.UseSoapEndpoint<ISampleService>("/Service.asmx", new
SoapEncoderOptions(), SoapSerializer.XmlSerializer);
});
Do I have to set the Endpoints in the Controller? The same way im
doing it with my normal REST APIĀ“s? I didnt find an answer for this on
the Internet
Well, for Web Service integration within the asp.net core project regardless of version there are two prerequisite:
Prerequisite:
Either your web service must be running and URL should available for calling
Or must have Valid WSDL file in local machine.
Common Implementation For Both:
Following steps would be same for both asmx and wsdl integration.
In addition, please be sure that, I have used Microsoft Visual Studio Community 2022
Version 17.3.6 while preparing this answer.
Step:1
Step:2
Step:3
Implementation Using asmx URL:
Note: If your Web Service up and running it will start adding the reference without any issue.
Implementation Using WSDL file:
Note: You should select path for your valid wsdl file here. Ignore my files here, you outght to choose your wsdl file instead.
Use Your Service Inside Your Web API/MVC Controller
Now, In your Web API project, you could use a service reference added earlier. Like below
Please note that, you should call the method according to the WCF service's method.
var serviceReference1 = new ServiceReference1.Service1Client();
var result = await serviceReference1.GetDataAsync(1) ;
If you still encounter any further issue for integration you could refer to our official document for more details here

Is Azure storage supported in Azure Static Web App functions?

I'm working on an API for an Azure Static Web App. The web app is implemented in Angular (although that isn't important for this question), and the API is implemented in C# (NET 6). Deployment to Azure is via a GitHub action.
I can create an HTTP trigger API endpoint that works fine, like so:
public static class Tester
{
[FunctionName("Tester")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "v1/tester")] HttpRequest req,
ILogger log)
{
return new OkObjectResult("Hello World");
}
}
I'm also able to access this directly via the SWA URL: https://<sitename>.azurestaticapps.net/api/v1/tester.
However, as soon as I add a reference to an Azure storage NuGet package to the project file (specifically Microsoft.Azure.WebJobs.Extensions.Storage.Blobs), making no other changes to the code, the API endpoint no longer works once deployed (although it will work locally).
On deploying the code with that package referenced in the .csproj, hitting the API endpoint gives a 503 status code with the response:
Function host is not running.
I enabled Application Insights for this static web app, and a CryptographicException is being thrown on startup:
An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information. For more information go to http://aka.ms/dataprotectionwarning Could not find any recognizable digits.
(The link in the message doesn't go anywhere useful).
I'm presuming this has something to do with the AzureWebJobsStorage setting, which cannot be set in an Azure Static Web App (for whatever reason).
Based on all of the above, it would seem that using Azure storage from within a static web app C# function is verboten. However, I can't find that stated explicitly online anywhere. Has anybody got this kind of thing to work?
I removed the following nuget packages to make it working:
Microsoft.Azure.EventGrid
Microsoft.Azure.WebJobs.Extensions.EventGrid
I decomposed my http functions to a separate project because SWA does not support the EventTriggers right now.

How to track dependencies, exceptions and requests for Live Metrics in ASP.NET MVC app?

I've configured Live Metrics for my ASP.NET MVC app with target framework 4.7.2 using the tutorial given in Microsoft Docs:
https://learn.microsoft.com/en-us/azure/azure-monitor/app/live-stream#enable-livemetrics-using-code-for-any-net-application
In this tutorial, they've given a sample client.TrackDependency() and client.TrackRequest() call in the end. They've also mentioned in comments that those are samples and we must replace it with actual application logic to work. I'm new to all these and I don't know what to replace. Since my application is huge and has a lot of methods, it is impractical to call the tracking methods in each method or controller. Since it is not ASP.NET Core, there are no middlewares and I have to enable Live Metrics by code too. I've added the code in the Application_Start() of Global.asax.cs of my application, so that it runs during startup.
This is what I've done so far,
// Create a TelemetryConfiguration instance.
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration telemetryConfig = Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.CreateDefault();
telemetryConfig.InstrumentationKey = System.Web.Configuration.WebConfigurationManager.AppSettings["AppInsightsInstrumentationKey"];
QuickPulseTelemetryProcessor quickPulseProcessor = null;
telemetryConfig.DefaultTelemetrySink.TelemetryProcessorChainBuilder
.Use((next) =>
{
quickPulseProcessor = new QuickPulseTelemetryProcessor(next);
return quickPulseProcessor;
})
.Build();
var quickPulseModule = new QuickPulseTelemetryModule();
// Secure the control channel.
// This is optional, but recommended.
//quickPulseModule.AuthenticationApiKey = "YOUR-API-KEY-HERE";
quickPulseModule.Initialize(telemetryConfig);
quickPulseModule.RegisterTelemetryProcessor(quickPulseProcessor);
// Create a TelemetryClient instance. It is important
// to use the same TelemetryConfiguration here as the one
// used to setup Live Metrics.
TelemetryClient client = new TelemetryClient(telemetryConfig);
// I need some method by which I can track all the requests, exceptions,
// dependencies etc. here.
I searched and searched a lot for a solution but couldn't get a concrete solution. As a last resort I'm requesting you guys to help me. What can I do to track all requests, dependencies, exceptions, etc. globally...?
If you're using the ASP .NET MVC with .Net Framework 4.7.2 Version, You need to configure the Application Insights code related to the .NET Specific SDK Type like Framework, Core, Console, etc.
From the given MS doc, you're following the console app related app insights code but as you're using the MVC Web App so you need to follow this code from this section of documentation.
Here is the workaround I tried to get the live metrics, logs in the Application Insights of Azure Portal.
In Visual Studio, Created the asp .net mvc web app (.NET Framework version 4.7.2)
Added the Application Insights Instrumentation Key in the ApplicationInsights.config
Follow the above documentation as it says to create a new folder in the root and add the ErrorHandler class and modify the FilterConfig class from the App_Start folder in order to match your ErrorHandler Class Functionality.
And then deploy the MVC Web App. While publishing configure the Application Insights in Visual Studio Publish Window like below:
After deploying the App, Open the Web App URL in the browser, then you can see the logs in overview tab and also in App Insights Resource Live Metrics Page as you can see the screenshots below:
I found a solution myself. I found out that I can use the Application_BeginRequest() event handler to catch all requests inside Global.asax itself. All I had to do is to store the TelemetryConfiguration into a global variable and access it from the Application_BeginRequest() handler. This is what I did:
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
protected void Application_Start()
{
RegisterLiveMetrics();
// Omitted the other code for brevity
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
var telemetryConfig = Application["TelemetryConfig"] as TelemetryConfiguration;
TelemetryClient client = new TelemetryClient(telemetryConfig);
var httpContextCurrent = HttpContext.Current;
client.TrackRequest(httpContextCurrent.Request.RawUrl, DateTimeOffset.Now,
TimeSpan.FromMilliseconds(230), httpContextCurrent.Response.StatusCode.ToString(),
true);
}
private void RegisterLiveMetrics()
{
// Create a TelemetryConfiguration instance.
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration telemetryConfig = Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.CreateDefault();
telemetryConfig.InstrumentationKey = System.Web.Configuration.WebConfigurationManager.AppSettings["AppInsightsInstrumentationKey"];
QuickPulseTelemetryProcessor quickPulseProcessor = null;
telemetryConfig.DefaultTelemetrySink.TelemetryProcessorChainBuilder
.Use((next) =>
{
quickPulseProcessor = new QuickPulseTelemetryProcessor(next);
return quickPulseProcessor;
})
.Build();
var quickPulseModule = new QuickPulseTelemetryModule();
quickPulseModule.Initialize(telemetryConfig);
quickPulseModule.RegisterTelemetryProcessor(quickPulseProcessor);
Application["TelemetryConfig"] = telemetryConfig;
}
Luckily this seems to work fine. Currently I'm only tracking requests.
Note: I'm not sure about the namespaces mentioned above.

Azure - This Service is unhealthy .NET Backend

I have constructed an API using webapi2.2.
When I deploy the API to Azure I get the Service Unhealthy Message...when I check the logs of my API the log gives the error message
"Boot strapping failed: executing 'WebApiConfig.Register' caused an
exception: 'Parameter count mismatch.'.
The Application Start function is below
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
And my WebApiConfig.cs has the following:
public static void Register(HttpConfiguration config)
{
config.EnableCors();
config.Formatters.JsonFormatter.
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));.......
Another question here: The api implements its own Security mechanism (I used the following as a reference http://bitoftech.net/2014/12/15/secure-asp-net-web-api-using-api-key-authentication-hmac-authentication/). Would this implementation work in Azure or would you have to make use of the x-zumo header authorisation mechanism?
I found the resolution to this - I believe that the problem is caused by the fact that I have another mobile services app running in my Azure account. That app was built awhile ago - early 2015 and used the register procedure with no parameters
public static void Register(){.....}
I think that this may have confused the service operation (the fact that one app has a register without parameters and the other has a register with one parameter). To resolve the issue with my new app I removed the config parameter, and build the config settings in the register function see below
public static void Register()
{
ConfigOptions options = new ConfigOptions();
HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options));
config.EnableCors();.....
Remember though you will need access to the using Microsoft.WindowsAzure.Mobile.Service namespace...this can be obtained by installing the nuget package WindowsAzure.MobileServices.Backend
Hope this helps someone who has similar problems

SignalR calling client method from outside hub using GlobalHost.ConnectionManager.GetHubContext doesn't work. But calling from within the hub does

I'm trying to call a client method from within a .net Web API controller action.
Can I do this?
The only post I can find that comes close to what I am looking to do is this one:
SignalR + posting a message to a Hub via an action method
In there a message is sent from within an asp.net MVC controller action using GlobalHost.ConnectionManager.GetHubContext.
When I try that inside my Web API action no errors are thrown, but the method "methodInJavascript" is never invoked on the client side.
Public ActionResult MyControllerMethod()
{
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.All.methodInJavascript("hello world");
// or
context.Clients.Group("groupname").methodInJavascript("hello world");
}
When I set a break point inside that action, I see that the code is being reached and executed. Nothing happens on the javascript client side though.
Why? Is Web API so different under the hood that this won't work? Has anyone else tried it and had success?
When I call the "methodInJavascript" from "within" my hub, it works perfectly. Just won't work when called from within a .net Web API controller action.
UPDATE:
After researching this issue I have no solution. I can only assume there is something missing from examples like this Server to client messages not going through with SignalR in ASP.NET MVC 4 and this calling SignalR hub from WebAPI controller issues like maybe there is an additional configuration step to enable calling from a HubContext or something. The code I initially posted here is like that which appears in those examples has not been demonstrated to be flawed in any way. Can anyone see a flaw in the code? Calling from html works. I do it extensively in my apps and never experience an issue. I have never seen a call from the HubContext in an API controller work. No errors. Just no results on the client.
SOLVED (kind of):
Code above does indeed work as is when published. Does not work in Visual Studio dev environment via localhost though. No errors but no result on the client end. Publishing the code as is to a real server on the web does indeed work. I never thought there'd be a difference so I never tried. Figured if it didn't work locally it wouldn't work published. It's working live now but I'm wondering why it doesn't work via localhost in the dev environment. Can't test locally with breakpoints and such.
I have a feeling it's that signalr virtual directory. Something is different when run locally vs published. Not sure what but I see lots of posts like http://www.bitwisejourneys.com/signalr-hosting-in-iis-a-nasty-gotcha/. Reading now to see if there's a way to have it work both locally and published.
I came across with same issue couple days ago. That took my 2 days to find solution and resolve it. After some serious investigate the problems root cause was the signalr dependency resolver that I set customly.
At the end I found this link and that was saying this:
Replacing the DependencyResolver
You can change the DependencyResolver to use your DI container of
choice by setting GlobalHost.DependencyResolver.
NOTE: DO NOT override the global resolver in PreApplicationStart, it
will not work, or it'll work only sometimes. Do it in
PostApplicationStart (using WebActivator) or in Global.asax.
The important place here the NOTE. Of course after signalr 2.0 this documentation become deprecated. So I mixed some of here with the new SignalR API. In new SignalR API not using WebActivatorEx anymore. OwinStartup preferred instead of WebActivator.
[assembly: OwinStartupAttribute(typeof(YourNamespace.Startup))]
namespace YourNamespace
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
//IoC container registration process
UnityConfig.RegisterComponents();
UnityConfig.Container.RegisterType<AHub, AHub>();
HubConfiguration config = new HubConfiguration();
config.EnableJavaScriptProxies = true;
//You should remove your dependency resolver code from here to Global.asax Application_Start method. Before setting the MVC properties.
//config.Resolver = new SignalrDefaultDependencyResolver(UnityConfig.Container); // your dependency resolver
//
app.MapSignalR(config);
}
}
}
And in your global.asax
namespace YourNamespace
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
//Here your SignalR dependency resolver
GlobalHost.DependencyResolver = new SignalrDefaultDependencyResolver(UnityConfig.Container);
//other settings goes on
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
I dont want to send all the code here, for showing up the real problem.
So for me everything works fine for now. Dependency injection also works too. But the bad part is everywhere that I searched David Fowler was saying "Its by design". I started to think is this design really a necessary or a mistake.
Hope it helps somebody else who makes research for same problem.
I had the same issue, and it is related to IoC (with whatever such as ninject or castle).
If you set the global dependency resolver to your IoC manager, it will also replace the SignalR inner pipeline resolution. This makes your SingleTon client hub, not work correctly.
I solved it by only having the Server Hubs being IoC-ed
The code below requires SignalHubActivator (you can find it on the internet)
Now, GlobalHost.ConnectionManager.GetHubContext will return the single instance AND client methods will be called correctly again!
//configuration.Resolver = signalrDependency ; dont, this will cause GlobalHost.ConnectionManager to be intercepted by Castle
configuration.Resolver.Register(typeof(IHubActivator),
() => new SignalHubActivator(container));

Categories