How can I create a new HttpContext? - c#

public void getContent() {
string VirtualPath = "~/Content.aspx";
var page = BuildManager.CreateInstanceFromVirtualPath( VirtualPath, typeof( Page ) ) as IHttpHandler;
page.ProcessRequest( HttpContext.Current );
}
I'm using that function to load the content from different files, but the "page.ProcessRequest( HttpContext.Current )" inserts the content at the current context, and what I need is the function to return the content of the specified file.
I wonder if there's a working way to create a new HttpContext, so that "page.ProcessRequest" don't insert anything into the current response.

Oded is correct as far as I know. You can't easily create your own instance of the HttpContext. However you can still achieve your goals thorugh other means.
Use a Server.Execute. http://msdn.microsoft.com/en-us/library/ms150027.aspx.
You can specify the HttpHandler to execute along with a TextWriter to dump the content into.

You can't create a new HttpContext, not without lots of work arounds.
It is one of the failings of ASP.NET and the BCL - makes web applications untestable (or at least very difficult to test without HttpContext.
I am not clear on your requirement what I need is the function to return the content of the specified file - can you please explain exactly what you mean by that?

Check out Pex/Moles its includes a mocking framework that can mock almost any type or member, even if its sealed or static.
(it does this by using a custom test host)

Related

C# dotnet core 2 pass data from middleware/filter to controller method

currently we are writing a web application with dotnet core 2.
We actually create some kind of multi-hosting platform where we can register new clients based on the url passed to our application.
However currently we wanted to create a middleware/filter to validate our client's.
Actually what we wanted to do is pull an object from the database and check if it exists, if yes, we want to call the controller method and make the object accessible, if it does not exist, we actually want to abort and show an error page.
What we already have done is created a filter/middleware that does exactly that, however we couldn't figure out a way to access the object that we already pulled in our filter/middleware inside the controller method.
is there actually any documentation for doing that?
I actually tried to figure it out from:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware?tabs=aspnetcore2x
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters
but they don't describe a way to do it, only to actually do something before/after the action.
You could add the object to the context using HttpContext.Items which the docs state:
The Items collection is a good location to store data that is needed only while processing one particular request. The collection's contents are discarded after each request. The Items collection is best used as a way for components or middleware to communicate when they operate at different points in time during a request and have no direct way to pass parameters.
For example, in your middleware:
public class MySuperAmazingMiddleware
{
private readonly RequestDelegate _next;
public MySuperAmazingMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext context)
{
var mySuperAmazingObject = GetSuperAmazingObject();
context.Items.Add("SuperAmazingObject", mySuperAmazingObject );
// Call the next delegate/middleware in the pipeline
return this._next(context);
}
}
Then later on in your action method, you can read the value:
var mySuperAmazingObject = (SuperAmazingObject)HttpContext.Items["mySuperAmazingObject"];
One way of doing it (not saying it's the only or the best) is to have DI inject a proxy of the object, you set the real value of the object in your middleware, then you can access it from the proxy in the controller.
Note: if you'll pass the proxy object in the method call instead of controller, don't forget to mark it with [FromServices] attribute.
Another way would be adding the object to the request Items property. but when you read it you'll need casting from object to your actual class.

Retrieving HttpContext in a Custom NLog Target

I may me missing something basic here - but is it possible to retrieve the HttpContext.Current in a custom NLog event?
I am trying to give each request a unique Guid so that I can correlate logging messages to a single event (i.e, tie together each log event for a single request). So, I want to store this Guid in HttpContext.Current.Items, then retrieve it in the NLog target and include it in the log message.
Here is my example target where I'd like to access HttpContext.Current:
[Target("AzureTableTarget")]
public class AzureTableTarget : TargetWithLayout
{
public AzureTableTarget()
{
_appSettings = IoCResolver.Get<IAppSettings>();
}
protected override void Write(LogEventInfo logEvent)
{
var correlationId = HttpContext.Current; //This is always null
var batchOperation = new TableBatchOperation();
CxLogEventBuilder.Build(_appSettings, logEvent).ForEach(batchOperation.Insert);
_loggingTable.ExecuteBatchAsync(batchOperation);
}
}
Nowadays it's easier to retrieve the HTTP Context in a NLog target (works for ASP.NET and ASP.NET Core)
Install NLog.Web (ASP.NET) or NLog.Web.AspNetCore (ASP.NET Core) package
For ASP.NET core, follow the ASP.NET Core - NLog setup
Inherit from AspNetLayoutRendererBase (namespace NLog.Web.LayoutRenderers)
Get the request by calling var context = HttpContextAccessor.HttpContext;
Example:
[LayoutRenderer("aspnet-sessionid")]
[ThreadSafe]
public class AspNetSessionIdLayoutRenderer : AspNetLayoutRendererBase
{
protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
var context = HttpContextAccessor.HttpContext;
var contextSession = context?.Session();
if (contextSession == null)
{
InternalLogger.Debug("HttpContext Session Lookup returned null");
return;
}
builder.Append(contextSession.SessionID); // ASP.NET Core: contextSession.Id
}
}
PS: there are currently many predefined renderers for ASP.NET (Core): https://nlog-project.org/config/?tab=layout-renderers&search=aspnet
If your custom target should capture one (or more) context-specific values, then I recommend that your target inherits from TargetWithContext (or AsyncTaskTarget).
It gives the ability to setup and capture contextproperty-items. Where the Layout can be assigned to capture context-details. Examples of possible context-details easily available from HttpContext:
https://nlog-project.org/config/?tab=layout-renderers&search=package:nlog.web.aspnetcore
For more details about writing custom-targets:
https://github.com/NLog/NLog/wiki/How-to-write-a-custom-target-for-structured-logging
https://github.com/NLog/NLog/wiki/How-to-write-a-custom-async-target
Btw. there already exists this custom target that nicely inherits from AsyncTaskTarget:
https://www.nuget.org/packages/NLog.Extensions.AzureCosmosTable/
This article about Working with HttpContext.Current might help. The key, for you, might be that when control passes from one thread to another HttpContext.Current in the new thread can be null.
Here is another question/answer from here on SO that describes HttpContext.Current being null in the context of a web service. The accepted answer suggests turning on ASP.Net compatibility in your web.config file.
I don't know of either of these will help, but they might. I found them by googling for "HttpContext.Current is null", which yielded quite a number of hits. I have done very little ASP.NET development, so I can't really comment on HttpContext.Current from my own personal experience.
Given your use case, I would suggest that you look into System.Diagnostics.CorrelationManager.ActivityId.
One nice feature of ActivityId is that it is "flowed" from parent threads to child threads (including thread pool threads). I think that it works well with Tasks and Parallel operations. Works well meaning that the ActivityId, as set in a parent thread, has the expected value in a child thread.
There is not a LayoutRenderer for ActivityId, but it easy enough to write one. See an example (written against NLog 1.0) here:
Most useful NLog configurations
I'm pretty sure that the "EstimatedBufferSize" stuff is no longer needed, so something like will probably work:
[LayoutRenderer("ActivityId")]
class ActivityIdLayoutRenderer : LayoutRenderer
{
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
builder.Append(Trace.CorrelationManager.ActivityId);
}
}
If you go this route, you might consider adding a Format property to the ActivityIdLayoutRenderer to allow you to specify the guid format. See this answer (from me). It contains a lot of useful information about working with guids.
NewGuid vs System.Guid.NewGuid().ToString("D");
See this source file (in NLog's git repository) for an example of how you can implement and use such a Format property:
https://github.com/NLog/NLog/blob/master/src/NLog/LayoutRenderers/GuidLayoutRenderer.cs

How to use Delta<T> from Microsoft ASP.NET Web API OData with Code First\JsonMediaTypeFormatter

What is the issue?
I am trying to enable patching in my ASP.net web api app. I'm using code first entity framework.
I have the following method header which I can set a breakpoint in and it will hit:
[AcceptVerbs("PATCH")]
public async Task<HttpResponseMessage> Patch(long appId, long id, Delta<SimpleFormGroup> formGroup)
However when I call formGroup.Patch(entity), no changes are made to my entity. If I put the following into the immediate window:
formGroup.GetChangedPropertyNames()
Then this collection is empty, which seems wrong.
What have I tried?
I have been referring to the following examples
http://techbrij.com/http-patch-request-asp-net-webapi
http://www.strathweb.com/2013/01/easy-asp-net-web-api-resource-updates-with-delta/
It seems to be a problem with the Json MediaType Formatter not knowing how to build the Delta object correctly, however in the 2nd link filip does seem to suggest that it should work without the oDataMediaTypeFormatter.
I have started down the line of trying to serialise my model to EDMX representation, then from there extract the CSDL so I can create an oDataMediaTypeFormatter, but I have hit a snag there too, plus it seems a bit overkill.
If anyone could shed any light on this it'd be much appreciated. Let me know if any more information is needed.
EDIT:
Here is the class definition for SimpleFormGroup:
public class SimpleFormGroup
{
public int LastUpdate;
public string Identifier;
public string Title;
public int DisplayOrder;
}
And here is the data that I am sending:
Content-Type: 'application/json'
{ "DisplayOrder" : "20 }
Interesting, it looks like Delta<T> with int members doesn't work in JSON.
Unfortunately, Delta<T> was created specifically for OData. If Delta<T> appears to be working with any formatter other than OData, it's a coincidence rather than being intentional.
The good news though is that there's nothing stopping you from defining your own PATCH format for JSON, and I'd be surprised if no one has already written one that works better with Json.NET. It's possible that we'll revisit patching in a future release of Web API and try to come up with a consistent story that works across formatters.
Thanks to Youssef for investigating and discovering why things weren't working. Hopefully that can get solved down the line.
I managed to crack this myself in the end after poring over the oData package source. I chose to implement another MediaTypeFormatter that wraps up the logic as it provides easy access tio HttpContent, but there are other ways to achieve this.
The key part was figuring out how to interpret the code first model, see the commented line below:
public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
var builder = new ODataConventionModelBuilder();
// This line will allow you to interpret all the metadata from your code first model
builder.EntitySet<EfContext>("EfContext");
var model = builder.GetEdmModel();
var odataFormatters = ODataMediaTypeFormatters.Create(model);
var delta = content.ReadAsAsync(type, odataFormatters).Result;
var tcs = new TaskCompletionSource<object>();
tcs.SetResult(delta);
return tcs.Task;
}
Hope this saves someone some trouble!

How can I get the URL of the current page from within a C# App_Code class?

I have a logging class that, well, logs things. I would like to add the ability to automatically have the current page be logged with the messages.
Is there a way to get the information I'm looking for?
Thanks,
From your class you can use the HttpContext.Current property (in System.Web.dll). From there, you can create a chain of properties:
Request
Url and RawUrl
The underlying object is a Page object, so if you cast it to that, then use any object you would normally use from within a Page object, such as the Request property.
It's brittle and hard to test but you can use System.Web.HttpContext.Current which will give you a Request property which in turn has the RawUrl property.
public static class MyClass
{
public static string GetURL()
{
HttpRequest request = HttpContext.Current.Request;
string url = request.Url.ToString();
return url;
}
}
I tried to break it down a little :)
In the past I've also rolled my own logging classes and used Console.Writeln() but really there are a number of good logging options that already exist so why go there? I use NLog pretty much everywhere; it is extremely flexible with various log output destinations including console and file, lots of log format options, and is trivial to set up with versions targeting the various .net frameworks including compact. Running the installer will add NLog config file options to the Visual Studio Add New Item dialog. Using in your code is simple:
// declare in your class
private static Logger logger = LogManager.GetCurrentClassLogger();
...
// use in your code
logger.Debug(() => string.Format("Url: {0}", HttpContext.Current.Request.Url));

Path Problem in ASP.net

I am trying to do the following
I am building asp.net website with c# language
I want to read a text file from my project(the file is inside the project)
I tried to get the file Path by this way :
string path=Request.PhysicalApplicationPath+"filename.txt";
but I can't use The "Request" object from separated C# file ??
note: separated C3 file,I mean it's not related with aspx file
can you help me with my way or do you have another way ??
thx
I would recommend you passing the path to your library from the web application. So for example in your web app:
var path = Server.MapPath("~/filename.txt");
var result = BusinessLayer.SomeMethod(path);
You could also use HostingEnvironment in your class library but I would really advice you against it as it creates a dependency with System.Web which makes your class library tied to a web context and not unit testable friendly:
var path = Path.Combine(
HostingEnvironment.ApplicationPhysicalPath,
"filename.txt"
);
Using HttpContext.Current you have access to Request, Server, Response and other objects of the HTTP request.
but I can't use The "Request" object from separated C# file ??
I'm guessing you mean this is in a dll?
If so, then you can get to it by referencing system.web in the separate dll, and getting at the httpcontext.current object
I would use some sort of injection mechanism either to give the application root path to the class or a copy of the current context/request to the class that it can use. Essentially, you want to give the class the means to find the path (or even give it the path) rather than use a fixed dependency that is hard to recreate in testing. To simplify my example, I'll use the Request as you are doing, though, you could easily provide just the base path of the application as a string as well.
public class Foo
{
// HttpRequestBase may be more appropriate
private HttpRequest Request { get; set; }
public Foo( HttpRequest request )
{
this.Request = request;
}
public void Bar()
{
string path = Path.Combine( this.Request.PhysicalApplicationPath,
"filename.txt" );
...
}
}
Note that you could combine this with #Darin's ideas on how to calculate the server path as well.

Categories