Insights InstrumentationKey not populated after assignment in global.asax.cs - azure-application-insights

I have a .NET Framework 4.6.1 Web API solution which uses these Nuget packages:
<package id="Microsoft.ApplicationInsights" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.4.0" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.Web" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.WindowsServer" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.AspNet.TelemetryCorrelation" version="1.0.5" targetFramework="net461" />
In the global.asax.cs I have this code:
protected void Application_Start()
{
TelemetryConfiguration.Active.InstrumentationKey = ConfigurationManager.AppSettings[$"Insights-{EnvironmentConfig.EnvironmentName}"];
GlobalConfiguration.Configure(WebApiConfig.Register);
}
I can confirm that the ConfigurationManager.AppSettings[] value retrieval does indeed retrieve a valid Insights key.
In the controllers I have:
public class MyController : ApiController
{
TelemetryClient telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
[Route("api/DoSomething")]
[HttpPost]
public async Task<HttpResponseMessage> DoSomething()
{
try
{
// stuff happens
}
catch (Exception ex)
{
telemetryClient.TrackException(ex); // does not log
throw ex;
}
}
}
If I put a stop point at // stuff happens (there is actual code there, of course) and inspect the telemetryClient I can see the InstrumentationKey property is empty. This means I need to add a line everywhere I instantiate the TelemetryClient class and deliberately populated it.
How can I get it to be populated from global.asax.cs onwards?

Tried with both appsetting property ConfigurationManager.AppSettings & WebConfigurationManager.AppSettings I am able to view the Instrumentation key in TelemetryConfiguration & logs over Application Insights.
We are adding our instrumentation key in TelemetryConfig which is available in Telemetryconfig.
protected void Application_Start()
{
TelemetryConfiguration.Active.InstrumentationKey = ConfigurationManager.AppSettings[$"Insights-{EnvironmentConfig.EnvironmentName}"];
//TelemetryConfiguration.Active.InstrumentationKey = WebConfigurationManager.AppSettings[$"Insights-{EnvironmentConfig.EnvironmentName}"];
GlobalConfiguration.Configure(WebApiConfig.Register);
}

Related

How to keep Azure AD sign-on parameters with ASP.NET subdomains

I'm implementing, to an existing ASP.NET web application, the authentication via Azure AD and OpenIdConnect. All the packages version are listed at the end of the question
The application correctly contacts the Microsoft login service and the id_token is returned in the HTTP response, but when I try to access it inside the code with the Request structure, it appears to be Nothing.
(In the image below, Request.Url is the action url used within the Microsoft service returned form)
Going by exclusion in all the steps that the application performs, I think that the problem could be found in the URL structure generated by ASP.NET, in my case is http://localhost:50725/CONNECTION_ID/HomePage.aspx, where the CONNECTION_ID field is dynamic and reassigned for each connection.
Analyzing the HTTP packets, in fact, I find as a response to the sending of the token by Microsoft a "redirect" to the address linked to the user's connection, which, when loaded, loses the data related to authentication
<html>
<head>
<title>Object moved</title>
</head>
<body>
<h2>Object moved to here.</h2>
</body>
</html>
Based on other guides/answers and the Azure Application Registration form, I could not use any wildcards to define the return url for the authentication process.
How can I keep track of the authentication parameters to fully authenticate the user in my application?
EDIT
Debugging even more the code-flow I've found another issue, basically the Azure login procedure response triggers the Session_start event inside the Global.asax, therefore is creates a new Session.
The situation that I'm observing is the following:
The user opens the web application and tries the "Microsoft Login" option
The request is made to the login service
The id_token is passed via HTTP POST request back to the application, this triggers the Application_BeginRequest event inside the Global.asax
The request then triggers the Session_start event also from the Global.asax creating a new session and a new "base Url" for the current connection, therefore loosing track of the original session who called the authentication method and the id_token previously received
So, the real problem seems to be to keep the current session active and reload it with the authentication parameter provided by Microsoft
PACKAGES VERSION
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.Cors" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Cors" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.IdentityModel.Logging" version="5.3.0" targetFramework="net45" />
<package id="Microsoft.IdentityModel.Protocols" version="5.3.0" targetFramework="net45" />
<package id="Microsoft.IdentityModel.Protocols.OpenIdConnect" version="5.3.0" targetFramework="net45" />
<package id="Microsoft.IdentityModel.Tokens" version="5.3.0" targetFramework="net45" />
<package id="Microsoft.Owin" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Cors" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Cookies" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.OpenIdConnect" version="4.2.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
<package id="System.IdentityModel.Tokens.Jwt" version="5.3.0" targetFramework="net45" />
</packages>
We have tried the same in our environment and it works fine.
To Authenticate Azure AD(Microsoft Identity) in asp.net application we need to provide app registration details in our appsettings.json in below format.
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "microsoft.onmicrosoft.com",
"TenantId": "xxxxxxxxxxxxxxxxxxb47",
"ClientId": "xxxxxxxxxxxxxxxxxx02",
"CallbackPath": "/signin-oidc",
"SignedOutCallbackPath": "/signout-callback-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
You need to add following Required packages , In my case .csproj as below:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-WebApplication11-xxxx027-0xx2-xxA-xxD-D39xxx</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.1" NoWarn="NU1605" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.1" NoWarn="NU1605" />
<PackageReference Include="Microsoft.Identity.Web" Version="1.16.0" />
<PackageReference Include="Microsoft.Identity.Web.UI" Version="1.16.0" />
</ItemGroup>
</Project>
Here is my program.cs file
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
builder.Services.AddRazorPages()
.AddMicrosoftIdentityUI();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.MapControllers();
app.Run();
Add AUTHORIZE attribute in homecontroller.cs as below:
SAMPLE OUTPUT FOR REFERNCE:-
signin:
Successfully signout:
For more information please refer this MICROSOFT DOCUMENTATION: Add sign-in to Microsoft to an ASP.NET web app

Rebus: Is it not possible to use Rebus.Castle.Windsor along with Rebus 5.3

While trying to use rebus castle windsor along with rebus 5.3 then giving compile time error that "IHanlderActivator" is defined in an assembly which is not referenced, must add a reference to assembly rebus 4.0
Is rebus castle windsor only compatible with rebus 4.0 now?
It's certainly possible.
I've just created a Console Application (.NET 4.7.2) and installed the
Rebus
Rebus.Castle.Windsor
Rebus.XmlConfig (because I can see you're using that)
NuGet packages, which in turn resulted in the following packages.config:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Castle.Core" version="4.2.0" targetFramework="net472" />
<package id="Castle.Windsor" version="4.1.0" targetFramework="net472" />
<package id="Newtonsoft.Json" version="11.0.1" targetFramework="net472" />
<package id="Rebus" version="5.3.1" targetFramework="net472" />
<package id="Rebus.Castle.Windsor" version="4.1.0" targetFramework="net472" />
<package id="Rebus.XmlConfig" version="4.0.0" targetFramework="net472" />
</packages>
With this little program:
namespace ConsoleApp1
{
class Program
{
static void Main()
{
using (var container = new WindsorContainer())
{
Configure.With(new CastleWindsorContainerAdapter(container))
.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "windsor-test"))
.Routing(r => r.TypeBasedRoutingFromAppConfig())
.Start();
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
}
}
}
}
I get this:
Could you try and check e.g. how your packages.config differs from mine?

Log4net not working in IIS7 on windows server 2008

Logs are not created on the server (Windows 2008) and IIS7. I had given absolute path as well as relative path.
I had given all rights to the log folder. I had included network user, IUsr and IIS_IUSRS, and gave permission to every one. also.
It is not writing logs to that folder
the entries on the web config is as follows
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
<log4net>
<logger name="GeneralLogger">
<level value="ALL" />
<appender-ref ref="RollingFile" />
</logger>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="C:\\vhosts\\staging.customerportal.com\\log\\CustomerPortal.log"/>
<appendToFile value="true"/>
<datePattern value="yyyyMMdd"/>
<rollingStyle value="Date"/>
<filter type="log4net.Filter.LevelRangeFilter">
<acceptOnMatch value="true"/>
<levelMin value="DEBUG"/>
<levelMax value="FATAL"/>
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %X{addr} %-22.22c{1} %-18.18M - %m%n"/>
</layout>
</appender>
</log4net>
I had tried giving single slash and well as double slash in the file value in web config nothing works.
The code in the global.asax.cs is
public class MvcApplication : System.Web.HttpApplication
{
private static log4net.ILog log = log4net.LogManager.GetLogger(typeof(MvcApplication));
protected void Application_Start()
{
log4net.Config.XmlConfigurator.Configure();
}
code in assemblyinfo.cs is
[assembly: XmlConfigurator(ConfigFile="web.config", Watch=true)]
I had tried with this code and also without this code in assemblyinfo.cs
It is not working.
Where as When I use absolute path in localhost the logs are written to that folder properly
It fails on the server
I had tried both these options in the controller file
//private static log4net.ILog log =
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType) ;
private static log4net.ILog log = log4net.LogManager.GetLogger("GeneralLogger");
I had tried a path which does not exists, it did not created folder.
Please help me. Please help me how to enable logs using log4net in server
You are initializing your logger before configuring the logmanager (actually you configuring it twice) by calling the Configure on Application_Start.
Option 1:
public class MvcApplication : System.Web.HttpApplication
{
private static log4net.ILog log = log4net.LogManager.GetLogger(typeof(MvcApplication));
protected void Application_Start()
{
//Remove: log4net.Config.XmlConfigurator.Configure();
}
And keep:
[assembly: XmlConfigurator(ConfigFile="web.config", Watch=true)]
Option 2:
public class MvcApplication : System.Web.HttpApplication
{
private static log4net.ILog log;
protected void Application_Start()
{
log4net.Config.XmlConfigurator.Configure();
log = log4net.LogManager.GetLogger(typeof(MvcApplication));
}
And remove:
//Remove: [assembly: XmlConfigurator(ConfigFile="web.config", Watch=true)]

Intermittent problems with SignalR Hubs (in the Cloud) callback from Server to Client method

So far, SignalR Hubs has been working perfectly with a locally hosted website in IIS 7.5 on my dev machine. I have the client making a signalr call to the server on a click event, then the server does a 20 second thread delay before sending a response back to the callback method on the client. This works consistently across all browsers. However, when I deploy my application to the Windows Azure Cloud, SignalR begins to have these intermittent problems. Specifically, there seems to be a problem with the server reaching the callback method on the client. I verified this by watching the network traffic in Chrome Dev Tools. I can clearly see the POST connection being made out by signalr. It sits in "pending" status for 20 seconds and then the POST successfully completes when the server responds back. However, the callback method (with a simple alert message) on the client-side doesn't always fire for some reason. NOTE: In my testing, I noticed some strange behavior that when the callback method is not firing, I could get it to fire by doing a normal download of a file (by using href = window.baseUrl + '/CloudStorage/DownloadZip?') and then clicking on the button that triggers the signalr. As I'm watching this in network traffic, somehow that window.baseUrl BOM command triggers the signalr to do a reconnect. Would appreciate any help!
EDIT: I am using IE 10, latest Chrome, and latest Firefox for all my testing. IE 10 seems to have the most issues with signalr when the app is in the cloud, which is a little strange to me since this is an MS product. Also, I'm using version 1.1.2 of SignalR.
Here are my code snippets:
SERVER SIDE:
[HubName("MultiFile")]
public class MultiFile : Hub
{
[HubMethodName("Send")]
public void Send(string DocID)
{
System.Threading.Thread.Sleep(20000);
// Call the addMessage method on caller client
Clients.Caller.addMessage(DocID);
}
}
CLIENT SIDE:
$('#dBtn').click(function () {
var docIds = sceneLayoutService.getSelection();
var href;
var docIdsParam;
if (docIds.length === 0) {
// signalr test code below
// Proxy created on the fly
var test_connection = $.connection.MultiFile;
// Declare a function on the MultiFile hub so the server can invoke it
test_connection.client.addMessage = function (message) {
alert(message);
};
// Start the connection
$.connection.hub.start().done(function () {
// Call the chat method on the server
test_connection.server.Send("you need to select one!");
});
return false;
}
else if (docIds.length == 1) {
docIdsParam = "docId=" + docIds;
href = window.baseUrl + '/CloudStorage/Download?' + docIdsParam;
}
else {
docIdsParam = jQuery.param(docIds.map(function (value) {
//var parts = value.match(/[e[B|b]:\/\/[^\/]*\/\d*\/(\d*)/);
//return { "name": "docIds", "value": parts[1] };
return { "name": "docIds", "value": value };
}));
href = window.baseUrl + '/CloudStorage/DownloadZip?' + docIdsParam;
}
$(this).attr('href', href);
return true;
});
LIST OF PACKAGES:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Company.CONNECT.Analytics.eFWrapper" version="1.0.0.1" targetFramework="net40" />
<package id="Company.CONNECT.Analytics.Logging" version="1.0.0.11" targetFramework="net40" />
<package id="Company.CONNECT.Web" version="1.1.0.12" targetFramework="net40" />
<package id="Castle.Core" version="2.5.2" targetFramework="net40" />
<package id="Castle.Core-log4net" version="2.5.2" targetFramework="net40" />
<package id="Castle.Windsor" version="2.5.4" targetFramework="net40" />
<package id="Castle.Windsor-log4net" version="2.5.2" targetFramework="net40" />
<package id="CommonServiceLocator" version="1.0" targetFramework="net40" />
<package id="EnterpriseLibrary.Common" version="5.0.505.0" targetFramework="net40" />
<package id="EnterpriseLibrary.WindowsAzure.Configuration" version="5.0.1118.2" targetFramework="net40" />
<package id="EntityFramework" version="4.1.10331.0" targetFramework="net40" />
<package id="HtmlAgilityPack" version="1.4.6" targetFramework="net40" />
<package id="jQuery" version="2.0.2" targetFramework="net40" />
<package id="jQuery.UI.Combined" version="1.10.3" targetFramework="net40" />
<package id="jQuery.Validation" version="1.8.0" targetFramework="net40" />
<package id="jQuery.vsdoc" version="1.5.1" targetFramework="net40" />
<package id="log4net" version="1.2.10" targetFramework="net40" />
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Providers" version="1.1" targetFramework="net40" />
<package id="Microsoft.AspNet.Providers.Core" version="1.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.0.0" targetFramework="net40" />
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net40" />
<package id="Microsoft.Data.Edm" version="5.5.0" targetFramework="net40" />
<package id="Microsoft.Data.OData" version="5.5.0" targetFramework="net40" />
<package id="Microsoft.IdentityModel" version="6.1.7600.16394" targetFramework="net40" />
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.1" targetFramework="net40" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
<package id="Microsoft.WindowsAzure.ConfigurationManager" version="2.0.1.0" targetFramework="net40" />
<package id="Modernizr" version="2.6.2" targetFramework="net40" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net40" />
<package id="Owin" version="1.0" targetFramework="net40" />
<package id="Pkcs12ProtectedConfigurationProvider" version="1.0.1" targetFramework="net40" />
<package id="RequireJS" version="2.1.8" targetFramework="net40" />
<package id="SevenZipSharp" version="0.64" targetFramework="net40" />
<package id="SlowCheetah" version="2.5.5" targetFramework="net40" />
<package id="System.Spatial" version="5.5.0" targetFramework="net40" />
<package id="System.Web.Providers" version="1.2" targetFramework="net40" />
<package id="Unity" version="2.1.505.2" targetFramework="net40" />
<package id="Unity.Interception" version="2.1.505.2" targetFramework="net40" />
<package id="WebGrease" version="1.1.0" targetFramework="net40" />
<package id="WindowsAzure.Storage" version="2.0.5.1" targetFramework="net40" />
<package id="WindowsAzure.Storage" version="2.0.6.0" targetFramework="net40" />
</packages>
It turns out there are 2 Web Role instances running in my Windows Azure configuration. When there are multiple Azure instances running, a "backplane" needs to be used since we have no control over which instance the Azure Load Balancer chooses. This is why the messages sent back from the server to client were failing 50% of the time.
http://www.asp.net/signalr/overview/performance-and-scaling/scaleout-in-signalr

How to log communication of a WebService running on IIS 6.0?

I'm running an ASP.NET WebService on IIS 6.0 that shows a lot of HTTP 500 (probably just exceptions from the WebService) inside the log at %systemroot%\System32\LogFiles\W3SVC1 on a customers site.
Is it possible to log the content of those HTTP responses and there requests without modifying the WebService using IIS or a plug-in for IIS?
I thought of using Wireshark or Fiddler to sniff on the HTTP traffic but I would prefer to just turn on an option inside IIS to make him log the communication (this should not be to hard since it is logging the requested URLs anyway)
We've done this before using log4net. Here are the high level steps:
Create a log4net section in your web.config
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
and...
...
</system.web>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender,log4net">
<param name="File" value="c:\mysvc.log" />
<param name="AppendToFile" value="true" />
<param name="MaxSizeRollBackups" value="10" />
<param name="MaximumFileSize" value="1000000" />
<param name="RollingStyle" value="Size" />
<param name="StaticLogFileName" value="true" />
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
<!-- Setup the root category, add the appenders and set the default priority -->
<root>
<level value="DEBUG" />
<!--<priority value="DEBUG" />-->
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
...
In your Global.asax.cs call the log4net Configure()
protected void Application_Start(Object sender, EventArgs e)
{
log4net.Config.DOMConfigurator.Configure();
}
At the top of your web service .cs file, declare an instance of a log4net ILog
public class MyService : System.Web.Services.WebService {
{
private static readonly ILog log = LogManager.GetLogger(typeof(MyService));
In your web service methods, trap exceptions and log them
[WebMethod]
public void DoSomething()
{
try
{
// business logic
}
catch(Exception ex)
{
log.Error("Something bad happened", ex);
throw;
}
}
After these steps, in the example above any exceptions will appear in c:\mysvc.log
Create an HTTPModule and configure it in your ASP.NET configuration. You don't need to modify the existing Web Service's code (you needn't even have the sources), you just configure the HTTPModule in your Web.config.
In the HTTPModule, listen for events such as BeginRequest and EndRequest and you should be able to log the input to, and output from, the web service.
If you need to trap exceptions thrown in the web service, you could capture the Error event as described here and here.
Update:
According to this page, you can't use the Error event approach with web services as web service errors don't get routed to the Error event. Microsoft suggests that you use SOAP Extensions to log web service errors.

Resources