ASP.NET WebApi: How to check and create per-request context? - c#

In a self hosted ASP.NET Web Api, how can I:
Detect from a class if there's an "ambient" web api context. This is needed to avoid passing in metadata information on every service call. I'm looking for the equivalent of
System.Web.HttpRequest.Current != null
How can I attach metadata information associated with the current request. Again some of this metadata is just so prevalent that including them on every method and calls is way too painful. Think transaction, multi-tenant architecture and credentialings. I need a way to make this sort of information flow through between requests without cluttering the code.
In another word I also need the equivalent of this as explained here:
HttpContext.Current.Items["user" + X.ToString()]
I think I can still access them, as long as the WebApi is hosted on IIS, but I have got these self hosted and I need a way to keep track of the ambient UoW information - how can I do so?
A few notes:
I have also contemplated using per request DI and injecting a
request context into the managers, there are however a ton of legacy
code that wasn't set up for that (some of which are static) and I
don't have the guts to blow up production by doing such a major
refactor.
I have also used a thread static, static variable - the problem with such is that the thread gets recycled, and the process hosts multiple services, some of which aren't even WebApi... so sometimes my managers thought it's handling a WebApi request when in fact it's serving a WCF one.

The HttpRequestMessage instance has Properties dictionary that is intended for holding arbitrary per-request context.

Related

Architecture for DBContext in .Net Core application with multiple databases (1 per client)

I've inherited a .Net Framework application that wasn't really designed but thrown together as a portal application for clients, but then each client has their own database to store their data for security and data sovereignty reasons. The homepage loads basic data from a shared DB, but when the users naviagate to one of the pages, the site needs to connect to their specific database.
The app is written in C# with Angular and loosely follows MVC with the main context being passed around through DI, and I've just upgraded this to .Net 5. As there can be thousands of client databases that can't be registered as service connections in the startup, I'm trying to work out the best way to handle the DBContext for these client-specific databases. It seems to follow multi-tenancy principles in general, but the following are the concerns
Avoiding code repetition or adding lots of '= new DBContext' - use of DI would be preferable if possible with a TenantFactory or Database Interceptor
Ensuring that the connection is for the correct DB if the user has
multiple tabs for different clients open
Ensuring that the DB connection is disposed of when the client page is closed or the user
returns home to view another client
I realise that I can create a new DB Context per request, passing in the name of the DB each time, but is there a pattern or example that is better suited to this use case? Something like a DbCommandInterceptor at the DB level might work, but again if there are some examples of how to do this I can find them.
For your tenant context, make sure you use one of the AddDbContext overloads with a scoped optionsLifetime. Then you can provide a different connection string per instance, derived from any other scoped service.
services.AddDbContext<T>((sp, o) => {
var context = sp.GetService<IHttpContextAccessor>().Context;
o.UseSqlServer(... get the connection string here. From context.User? ...)
});
The simplest, most secure, and best way to do this is just what you said. Create a new DbContext per request, specifying the database name through some method of multi-tenancy isolation.
DbContext is designed to only live short term. Trying to make it live longer than a request will create memory and security issues. NEVER make a DbContext static (or singleton) in a multi-user application such as a web site.
The best practice is to inject a DbContext with a per request lifecycle. This will ensure the DbContext is destroyed after the request is completed, and all memory will be cleaned up.

How to measure Azure CosmosDB Request Units per web request?

In an ASP.NET Core Web Application I want to measure how many request units have been spent in a single web request. With this information I could identify "expensive" calls and look for optimizing them.
I know how to option the request unit count from a single CosmosDB Rest call. But this is a layered application where the persistence level that interacts with the ComosDB does not have access to the Request-Object in ASP.NET Core.
Is there a way to optain somehow some kind of request id? I wonder how Application Insights keeps track what are dependent internal calls for a specific web request.
Or is there a way to get this information in Application Insights?
This depends on multiple things including which SDK you are using.
If you are using the default Cosmos DB SDK also known as v2 SDK, then (assuming you enabled Application Insights support) Cosmos DB will only log it's dependency calls if you are using HTTP/HTTPS connection. TCP mode won't be captured by Application Insights. This means you would either have to use HTTPS which is bad in terms of performance or code something custom.
If you are using Cosmonaut then it comes out of the box with a general purpose EventSource which tracks each call as a dependency no matter the connection type and it also collects multiple metrics such as the RUs and a lot more. You would need to reference the Cosmonaut.ApplicationInsights nuget package and initialise the AppInsightsTelemetryModule like this:
AppInsightsTelemetryModule.Instance.Initialize(TelemetryConfiguration.Active);
or use the IoC alternative of:
services.AddSingleton(AppInsightsTelemetryModule.Instance);
This will give you logging for every action with detailed metrics such as the following (including the request charge):
You can then use a query like this to see spikes and further investigate, or just query for requests with Cosmos dependencies which exceed a threshold.
dependencies
| where type contains "Cosmos" and customDimensions.RequestCharge != ""
| summarize sum(toint(customDimensions.RequestCharge)) by bin(timestamp, 1m)
PS: You don't have to use the CosmosStore if you don't need it. Using the CosmonautClient instead of the DocumentClient will do the logging job as well.
This is available in the CosmosDB REST API response's header. You will need to create a correlation between your web call and the CosmosDB operations and then aggregate.
From the docs:
x-ms-request-charge This is the number of normalized requests a.k.a.
request units (RU) for the operation. For more information, see
Request units in Azure Cosmos DB.

How to make singleton static value securely accessible across all calls for a single HTTP request

I want a singleton accessible to the whole request and only to calls from that request.
I have a client with a requirement that the built-in server side session not be used.
Instead I need to rebuild the UserSession object each time based on the request's cookies and query string and validate it with the database.
There is some overhead in building the UserSession object, so I want to do it only once per request, as early as possible, and then reference that object later throughout the request.
Currently I am using OWIN middleware to call the facade object that actually builds it and then I am sticking the result in a class's static field decorated with [ThreadStatic]. I then use a custom Authorize attribute on my controllers to inspect that singleton to make sure it is valid.
First, is this secure across multiple requests? Stated differently, does the use of [ThreadStatic] ensure that each requests static object can never be accessed by another HTTP request, even from the same browser session.
Second, could I run into issues with using the TPL or other asyncronous programming approaches where the singleton instance should be available because it is the same request, but it is not because it might be executing on a different thread.
Lastly, am I doing wrong? Is there a better or precanned solution to this problem than what I am doing.
HttpContext.Current.Items is what I was looking for. A simple per-request collection that seems to exist for this type of scenario.

Difference between WebOperationContext.current and HttpContext.Current

I develop web and mobile applications for my customers. In my current architecture, many resources are shared between the web access and mobile access. An aspx page can be shown on web and be called to a web view in a mobile app. My question is :
What is the difference between WebOperationContext.Current and HttpContext.Current object?
From my understanding it is the same object, but I noticed that WebOperationContext.Current is null in some cases and I don't understand why.
WebOperationContext is typically used in a WCF REST method so that method can access the incoming request and outgoing response.
HttpContext is typically used in an ASP.NET WebForms page or web method for ASMX Web Service, when incoming request and outgoing response can be accessed.
They are designed for different project types (WCF REST/ASP.NET WebForms) so you should not use them in a wrong project type.
About when the value of .Current is null, that's even more complicated. Even if you are calling this property in the correct project type, you need to make sure the call is made on a proper thread. Only on the thread that handles the request (which also sends out the response) you can access the current context. On any other threads (background threads, or new threads created by you) you get null. This has been known for years but beginners still get it wrong sometimes.

ASMX service sharing a single class instance

I have a webservice with a .asmx extension which points to a class in my web application. After adding some code to output a debug log on application startup, I can see a new debug log is being created every time a user visits the page.
I was hoping that I could configure this web service to only ever use a single instance.
Meaning, when the first user visits the site it creates an instance of my webservice, and then all requests after are routed through that same class, sharing the same state.
Is this even possible?
Web sites are stateless in nature. Meaning, each request is generally unrelated to any other request.
That said, you could set the log as a static variable in your global.asax file. Be aware of threading issues.
Alternatively you might look at Elmah.
You seem to have a number of problems.
First of all, the ASMX technology is all but obsolete, and should not be used for new development. WCF should be used instead.
Next, yes, you can have multiple calls to the service share the same instance of your class. However, you'll have to prevent simultaneous access to this class unless it is thread safe. You should expect multiple service calls to call into the same class instance at the same time.
Finally, ASMX does not support singleton web services. The best you can do is to have multiple service calls all share the same object (carefully locked).

Categories