Is there an event raised the moment a website is published and updated?
I've tried Application_End in global.asax but that event does not seem to be raised.
I suggest to use both Kudu and Microsoft ASP.NET WebHooks preview.
Kudu is the engine behind git deployments, WebJobs, and various other features in Azure Web Sites (Kudu source is on GitHub)
With Kudu, Azure Web Sites have a support for web hooks. There is an event "PostDeployment" that will be invoked whenever a deployment is complete with the result of that deployment.
Microsoft ASP.NET WebHooks preview provides a common model for receiving and processing WebHooks from any number of WebHook providers includign support for Kudu (Azure Web App Deployment).
So you may use Kudu WebHooks to get notified when an update has been deployed. (But that will require using Git Deploy instead of other ways to publish your web site).
Here is the way to do it :
First Install the Microsoft.AspNet.WebHooks.Receivers.Azure Nuget package.
The, Add these two lines to the WebApiConfig.Register method:
config.InitializeReceiveKuduWebHooks();
config.InitializeReceiveAzureAlertWebHooks();
Then Add a handler :
public class KuduWebHookHandler : WebHookHandler
{
public KuduWebHookHandler()
{
Receiver = "kudu";
}
public override Task ExecuteAsync(string generator, WebHookHandlerContext context)
{
// Convert to POCO type
KuduNotification notification = context.GetDataOrDefault<KuduNotification>();
// Get the notification message
string message = notification.Message;
// Get the notification author
string author = notification.Author;
return Task.FromResult(true);
}
}
Then configure a secret that can validates that the WebHook requests indeed come from Kudu.
Use high-entropy values such as a SHA256 hash or similar, which you can get from http://www.freeformatter.com/hmac-generator.html. Also, set them through the Azure Portal instead of hard-coding them in the Web.config file
Also, set them through the Azure Portal instead of hard-coding them in the Web.config file.
There is a more complete Post on the subject here (http://blogs.msdn.com/b/webdev/archive/2015/10/04/receive-webhooks-from-azure-alerts-and-kudu-azure-web-app-deployment.aspx)
Hope this helps
Best regards
Stéphane
I figured it out. In the Application_Start event I bind
RoleEnvironment.Stopping += RoleEnvironmentStopping;
private void RoleEnvironmentStopping(object sender, RoleEnvironmentStoppingEventArgs e)
{
// do something ...
}
Related
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.
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.
We are currently developing a service that integrates service now and VSTS. When an incident created in servicenow, based on the category selected the integration creates a work item in the VSTS. This part we were able to accomplish. Now we need to send updates from VSTS workitems, if any, to servicenow incident. We have created a service hook that captures the work item event details when an update happens to work item.
Now,the problem that I am having is, how can I create an event listener that listens to the web hook and reads that information. Is an example available on how to create the event listener from web hooks?
I implemented something similar with github webhooks. I´ve used an asp.net web api in azure because in .netcore it´s still prerelease. You can look for it githubwebhookrepo
There is also a nuget package for vsts. I think it should be pretty much the same.
nuget
You will get a context with a payload json in it and there should be your event type.
public class GitHubWebHookHandler : WebHookHandler
{
public GitHubWebHookHandler()
{
this.Receiver = GitHubWebHookReceiver.ReceiverName;
}
public override Task ExecuteAsync(string generator, WebHookHandlerContext context)
{
JObject entry = context.GetDataOrDefault<JObject>();
return Task.FromResult(true);
}
}
Payload info: https://learn.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=vsts
In order to log the JSON of each WebApi request/response I have created a custom DelegatingHandler and added this to the MessageHandlers collection in WebApiConfig.cs and it works great.
In future though, I'd like to be able to enable this handler on other WebApi applications via web.config without having to actually modify WebApiConfig.cs.
By way of clarification, what I'm trying to achieve is analogous to what was possible in WCF where you could create a completely separate dll, drop it into the bin folder of a WCF service and add it into the WCF pipeline solely by editing the web.config file without having to modify the source of the service at all.
Is this possible in WebApi or can a custom DelegatingHandler only be added via code at runtime?
Modify the handler to check the config and perform its function if enabled otherwise just let the request pass through. if being used for logging make sure it is added early in the pipeline. Look into using middle-ware if possible.
public class LoggingHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
var appSetting = ConfigurationManager.AppSettings["LoggingHandlerEnabled"];
var enabled = true;
bool.TryParse(appSetting, out enabled);
if(enabled) {
//...Extract and log request
LogRequest(request);
}
// Execute the request and get the response
var response = await base.SendAsync(request, cancellationToken);
if(enabled) {
//...Extract details from response for logging
LogResponse(response);
}
return response;
}
private void LogRequest(HttpRequestMessage request) {
//... code removed for brevity
}
private void LogResponse(HttpResponseMessage response) {
//... code removed for brevity
}
}
With that in place then there would be no further need to modify any more code to enable/disable the handler. Update the config file and the handler will respect the setting.
After a bit of research I am answering my own question. It seems like this is not possible without having to modify the source of the target application. It might be possible to dynamically load or inject such a handler at startup if some thought was given during the writing of the application and knew to look for it. Another possible solution would be to create the logging handler as a nuget package and when the nuget package is installed into the target application the installer would add the dll and also create a WebActivator hook that added the handler to the MessagingHandlers collection in PostApplicationStartMethod. This might be the approach that involves that least amount of manual code change, but would still require recompilation and re-deployment of the target app.
Tracing in ASP.NET Web API 2
From the Tools menu, select Library Package Manager, then Package Manage Console.
In the Package Manager Console window, type the following commands.
Install-Package Microsoft.AspNet.WebApi.Tracing
Update-Package Microsoft.AspNet.WebApi.WebHost
The first command installs the latest Web API tracing package. It also updates the core Web API packages. The second command updates the WebApi.WebHost package to the latest version.
Open the file WebApiConfig.cs in the App_Start folder. Add the following code to the Register method.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code
config.EnableSystemDiagnosticsTracing();
// Other configuration code not shown.
}
}
This code adds the SystemDiagnosticsTraceWriter class to the Web API pipeline. The SystemDiagnosticsTraceWriter class writes traces to System.Diagnostics.Trace.
To see the traces, run the application in the debugger. In the browser, navigate to /api/values.
The trace statements are written to the Output window in Visual Studio. (From the View menu, select Output).
I have a web application deployed to azure but I don't know how to log errors.
For testing purposes I have this ForceError method:
public string ForceError()
{
throw new Exception("just a test exception");
return "ok";
}
Which causes and error like this:
On Azure I enabled all Diagnostic logs like this:
But the error I forced does not appear in selected storage container.
Do you know what should I do to start logging all the errors from the application?
I am afraid just throwing an exception doesn't work in Azure Web application logging.
ASP.NET applications can use the System.Diagnostics.Trace class to log information to the application diagnostics log. The four methods in example below correspond with the diagnostic log levels:
Trace.TraceError("Message"); // Write an error message
Trace.TraceWarning("Message"); // Write a warning message
Trace.TraceInformation("Message"); // Write an information message
Trace.WriteLine("Message"); // Write a verbose message
Besides the basic information for logged events, blob storage log additional information such as the instance ID, thread ID, and a more granular timestamp (tick format) in CSV.
A great article here about logging tips and tools.
See also the Reference to the official Azure Web Apps Logging Document.
On Azure Websites, best way to log would be Application Insights, you can use free version to get insights about crashes/speed/performance.
However, Application Insights is little slower if you enable everything. But if you customize it and enable only error logging, it would push all logs to your azure application insights account and you will be able to monitor/analyze it very nicely.
For more details:
https://azure.microsoft.com/en-in/documentation/articles/app-insights-api-custom-events-metrics/
Instead of automatically configuring Application Insights, I would suggest, take an empty project, setup application insights. Notice all added config files and nuget packages. There is some insight config file, except application key/signature, you can turn off everything.
Only when you want to track an exception manually, you can create TelemetryClient and call TrackException method. You can pass more details if you need.