Alternative to HttpRequestMessage SetContext method - asp.net-web-api

I have this code from codeplex
private async Task ExecuteChangeSet(
ChangeSetRequestItem changeSet,
IList<ODataBatchResponseItem> responses,
CancellationToken cancellation)
{
ChangeSetResponseItem changeSetResponse;
// Create a new ShoppingContext instance, associate it with each of the requests, start a new
// transaction, execute the changeset and then commit or rollback the transaction depending on
// whether the responses were all successful or not.
using (ShoppingContext context = new ShoppingContext())
{
foreach (HttpRequestMessage request in changeSet.Requests)
{
request.SetContext(context);
}
The complete sample code can be found here.
I downloaded the project and it is using .net framework 4.5
but in .NET Framework 4.6.1 the SetContext method is no longer present
I want to know how can I achieve the same in framework version 4.6.1?
I am basically creating a OData V3 Service which will be hosted in IIS.

You can go with creating your own functionality for setting the context and retrieve it where needed, with HttpRequestMessage extensions like:
Example class:
public static class HttpRequestMessageExtensions
{
private const string Context = "ShoppingContext";
public static void SetContext(this HttpRequestMessage request, ShoppingContext context)
{
request.Properties[Context] = context;
}
public static ShoppingContext GetContext(this HttpRequestMessage request)
{
object context;
if (request.Properties.TryGetValue(Context, out context))
{
return (ShoppingContext) context;
}
return null;
}
}
Usage:
//Setting context
request.SetContext(context);
//reading context
var context = request.GetContext();

Related

Store Workflow Activity Data When Publishing

I Need to store a specific activity data in another collection in database whenever a user publish a workflow in elsa.
I dont find any documentation, Please suggest me some resource or suggestion to achieve this. I have try to implement this with middleware. The Middleware code is
namespace WorkFlowV3
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class CustomMiddleware
{
private readonly RequestDelegate _next;
static HttpClient client = new HttpClient();
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
//Write Custom Logic Here....
client.BaseAddress = new Uri("#");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string path = "/api/test-middleware-call";
HttpResponseMessage response = await client.GetAsync(path);
await _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CustomMiddlewareExtensions
{
public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomMiddleware>();
}
}
}
But in this process, I cant fetch the specific activity data.
The easiest way to store information in your own DB in response to the "workflow published" event is by implementing a notification handler (from MediatR) that handles the WorkflowDefinitionPublished notification.
For example:
public class MyWorkflowPublishedhandler : INotificationhandler<WorkflowDefinitionPublished>
{
private readonly IMyDatabaseStore _someRepository;
public MyWorkflowPublishedhandler(IMyDatabaseStore someRepository)
{
_someRepository = someRepository;
}
public async Task Handle(WorkflowDefinitionPublished notification, CancellationToken cancellationToken)
{
var workflowDefinition = notification.WorkflowDefinition;
// Your logic to do a thing.
}
}
To register this handler, from your Startup or Program class, add the following code:
services.AddNotificationHandler<MyWorkflowPublishedhandler>();
Your handler will be invoked every time a workflow gets published.

Entity Framework 6 "DbContext has been disposed" exception

Something very strange is happening in production, and it only happens in production. I have a Web API running and in one of the APIs, there is a repository created in the constructor and used in the functions. This is how the flow of a request works:
HTTP request comes in
MVC API controller decides which "worker" class to instantiate and creates it using Activator.CreateInstance
API controller calls worker.OnExecute inside of a Task.Run() and returns the http response
Worker calls _engine.Execute
Each worker instantiates another "engine" class that has all of the logic.
The engine in case constructs 3 repositories created using a UnitOfWork that is created per engine instance, like so:
public class MyWorker : Worker
{
private readonly MyEngine _engine;
public MyWorker()
{
_engine = new MyEngine();
}
protected override WorkerResult OnExecute(JObject data, CancellationToken cta)
{
return new WorkerResult(HttpStatusCode.OK, _engine.Execute(data));
}
}
public class MyEngine : EngineBase
{
private BaseRepository<Order> OrderRepo { get; set; }
private BaseRepository<OrderItem> OrderItemRepo { get; set; }
public MyEngine()
{
OrderRepo = new BaseRepository<Order>(MyUnitOfWork);
OrderItemRepo = new BaseRepository<OrderItem>(MyUnitOfWork);
}
public string Execute(JObject data)
{
return IsOrderValid(data).ToString();
}
public bool IsOrderValid(JObject data)
{
var orderId = data.Value<int>("OrderId");
// Without this line it crashes. With this line it crashes
//OrderRepo = new BaseRepository<Order>(InternationalWork);
// This is where it crashes
Order order = OrderRepo.First(x => x.OrderID == orderId);
// more code
}
}
public class EngineBase : UnitOfWorker, IDisposable
{
private UnitOfWork _myUnitOfWork;
public EngineBase() { }
public UnitOfWork MyUnitOfWork
{
get
{
return _myUnitOfWork ?? (_myUnitOfWork = new UnitOfWork(new DbContextAdapter(new MyDbContext())));
}
}
}
This is the actual stack trace:
The operation cannot be completed because the DbContext has been disposed.
StackTrace1
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.LazyInternalContext.get_ObjectContext()
at System.Data.Entity.Internal.Linq.InternalSet`1.CreateObjectQuery(Boolean asNoTracking, Nullable`1 streaming, IDbExecutionStrategy executionStrategy)
at System.Data.Entity.Internal.Linq.InternalSet`1.InitializeUnderlyingTypes(EntitySetTypePair pair)
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
The stack trace shows "FirstOrDefault" because OrderRepo.First internally calls DbSet.FirstOrDefault, like so:
public virtual T First(Expression<Func<T, bool>> query)
{
return _dbSet.FirstOrDefault(query);
}
I'm stumped because each worker is created per http request. Each DBContext is created per engine instance so I don't know how it could be disposed when it was just created in the constructor. And this only happens on the production web server where I presume it's being called more. Any tips would be greatly appreciated.

Capturing and injecting HttpRequestMessage in Web API with Ninject

I've got a class that requires access to the HttpRequestMessage in my Web API service. At the moment, I've got the following code to capture the message in the pipeline and save it for later (based on this and this):
public class ContextCapturingControllerActivator : IHttpControllerActivator
{
private readonly IKernel kernel;
private HttpRequestMessage requestMessage;
public ContextCapturingControllerActivator(IKernel kernel)
{
this.kernel = kernel;
}
public IHttpController Create(HttpRequestMessage requestMessage,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
this.kernel.Rebind<HttpRequestMessage>()
.ToConstant<HttpRequestMessage>(requestMessage);
var controller = (IHttpController)this.kernel.GetService(controllerType);
this.requestMessage = requestMessage;
requestMessage.RegisterForDispose(
new Release(() => this.kernel.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action release;
public Release(Action release)
{
this.release = release;
}
public void Dispose()
{
this.release();
}
}
}
In my composition root, I configure the ControllerActivator:
kernel.Bind<IHttpControllerActivator>()
.To<ContextCapturingControllerActivator>();
The end result is that from the perspective of the configuration, the HttpRequestMessage is "magically" injected wherever it is requested since it is done for us inside the ControllerActivator. I have not been able to inject the message from my composition root. I'm also not crazy about the Rebind since it's there to avoid adding a new binding every time the service is called. I suspect it's due to the singleton nature of the Web API stack, but have not been able to sort out how to deal with that properly.
In general, I cannot use the latest unstable Nuget package of Ninject web api due to the error reported (and ignored) here.
Can anyone suggest the proper way to improve my code to make it a bit more clear and make life easier for future maintainers (and let's face it -- that's probably going to be me).
Thanks.
Here is what I did, but I believe it depends on Web API 2.0+.
I created an instance class that wraps the current context's http request:
public class HttpRequestMessageWrapper
{
private readonly HttpRequestMessage m_httpRequestMessage;
public HttpRequestMessageWrapper()
{
m_httpRequestMessage = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage;
}
public HttpRequestMessage RequestMessage
{
get
{
return m_httpRequestMessage;
}
}
}
Then I bound the HttpRequestMessage to the property with the ToMethod binding in request scope.
container.Bind<HttpRequestMessage>().ToMethod(ctx => new HttpRequestMessageWrapper().RequestMessage).InRequestScope();
I've tried the method that #Mackers proposed which is the cleanest way.... however, in my specific scenario, it didn't work due to a timing issue. For my case, I needed to inject an object into the apicontroller ctor and that object required the HttpRequestMessage. The HttpContext.Current.Items["MS_HttpRequestMessage"]isn't populated until the controller has been constructed and initialized and I couldn't find any other way to access it. So I resorted to creating a custom DelegatingHandler and rebinding the current request message as they come in.
public class CurrentHttpRequestMessageHandler : DelegatingHandler
{
[SecuritySafeCritical]
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
UpdateScopeWithHttpRequestMessage(request);
return base.SendAsync(request, cancellationToken);
}
internal static void UpdateScopeWithHttpRequestMessage(HttpRequestMessage request)
{
NinjectConfig.GetConfiguredKernel().Rebind<HttpRequestMessage>().ToMethod(ctx => { return request; })
.InRequestScope();
}
}
The GetConfiguredKernel is a static method I created to simply return the static Kernel instance already configured.
public class NinjectConfig
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
private static StandardKernel _kernel;
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static IKernel GetConfiguredKernel()
{
if (_kernel != null)
return _kernel;
return CreateKernel();
}
....
Then register the DelegatingHandler with the HttpConfiguration:
config.MessageHandlers.Add(new CurrentHttpRequestMessageHandler());
Building off of Macker's answer, System.Web has an HttpRequestBase class that you can use and simplify unit testing the code. Anywhere in the code that the request is required, specify the HttpRequestBase type as the constructor parameter and register it with the below method:
Ninject example:
Bind<HttpRequestBase>().ToMethod(context => new HttpRequestWrapper(HttpContext.Current.Request));
Unity example:
container.RegisterType<HttpRequestBase>(new InjectionFactory(_ => new HttpRequestWrapper(HttpContext.Current.Request)));

How to fake an HttpContext and its HttpRequest to inject them in a service constructor

In a console application, I would like to use a service that would normally need the current http context to be passed to its constructor. I am using Ninject, and I think I can simply fake an http context and define the proper binding, but I have been struggling with this for a few hours without success.
The details:
The service is actually a mailing service that comes from an ASP.Net MVC project. I am also using Ninject for IoC. The mail service needs the current http context to be passed to its constructor. I do the binding as follows:
kernel.Bind<IMyEmailService>().To<MyEmailService>()
.WithConstructorArgument("httpContext", ninjectContext => new HttpContextWrapper(HttpContext.Current));
However, I would like now to use this mailing service in a console application that will be used to run automated tasks at night. In order to do this, I think I can simply fake an http context, but I have been struggling for a few hours with this.
All the mailing service needs from the context are these two properties:
httpContext.Request.UserHostAddress
httpContext.Request.RawUrl
I thought I could do something like this, but:
Define my own fake request class:
public class AutomatedTaskHttpRequest : SimpleWorkerRequest
{
public string UserHostAddress;
public string RawUrl;
public AutomatedTaskHttpRequest(string appVirtualDir, string appPhysicalDir, string page, string query, TextWriter output)
: base(appVirtualDir, appPhysicalDir, page, query, output)
{
this.UserHostAddress = "127.0.0.1";
this.RawUrl = null;
}
}
Define my own context class:
public class AutomatedTasksHttpContext
{
public AutomatedTaskHttpRequest Request;
public AutomatedTasksHttpContext()
{
this.Request = new AutomatedTaskHttpRequest("", "", "", null, new StringWriter());
}
}
and bind it as follows in my console application:
kernel.Bind<IUpDirEmailService>().To<UpDirEmailService>()
.WithConstructorArgument("httpContext", ninjectContext => new AutomatedTasksHttpContext());
Unfortunately, this is not working out. I tried various variants, but none was working. Please bear with me. All that IoC stuff is quite new to me.
I'd answered recently about using a HttpContextFactory for testing, which takes a different approach equally to a console application.
public static class HttpContextFactory
{
[ThreadStatic]
private static HttpContextBase _serviceHttpContext;
public static void SetHttpContext(HttpContextBase httpContextBase)
{
_serviceHttpContext = httpContextBase;
}
public static HttpContextBase GetHttpContext()
{
if (_serviceHttpContext!= null)
{
return _serviceHttpContext;
}
if (HttpContext.Current != null)
{
return new HttpContextWrapper(HttpContext.Current);
}
return null;
}
}
then in your code to this:
var rawUrl = HttpContextFactory.GetHttpContext().Request.RawUrl;
then in your tests use the property as a seam
HttpContextFactory.SetHttpContext(HttpMocks.HttpContext());
where HttpMocks has the following and would be adjusted for your tests:
public static HttpContextBase HttpContext()
{
var context = MockRepository.GenerateMock<HttpContextBase>();
context.Stub(r => r.Request).Return(HttpRequest());
// and stub out whatever else you need to, like session etc
return context;
}
public static HttpRequestBase HttpRequest()
{
var httpRequest = MockRepository.GenerateMock<HttpRequestBase>();
httpRequest.Stub(r => r.UserHostAddress).Return("127.0.0.1");
httpRequest.Stub(r => r.RawUrl).Return(null);
return httpRequest;
}

SignalR in SharePoint

My project has a need for realtime user interaction and I think SignalR will solve my need. I'm technically on a SharePoint 2007 project, although I'm exclusively in application pages and thus barely use SharePoint at all. Regardless, I'm stuck in a 2.0 framework app pool in IIS.
My first approach was to try to create a 4.0 application as a sub-site. Unfortunately, that failed miserably. That approach works in a non-SharePoint world, but it appears that SharePoint has hijacked too much of the request pipeline for this approach to work for me.
So now I'm going down the path of creating a separate IIS Site that's 4.0 and using IIS rewrite rules to fake my app into thinking a particular subdirectory (/realtime/) is local and not a separate site so that I don't have to deal with cross domain request issues. The problem is I can't get IIS rewrite rules to rewrite to another http host (e.g. http://www.mySharepoint.com/_layouts/MySite/realtime/Hello.aspx to http://realtime.mySharePoint.com/Hello.aspx).
Any help with approach #1 or approach #2 or any alternative ideas would be greatly appreciated.
Here is what I did... Web App with signalR .net4.0, then your SharePoint Web App .net 2.
Add this to the global.asax in your Signalr project
RouteTable.Routes.MapHttpHandlerRoute("spproxy","spproxy/{*operation}", new SharePointRProxyHandler());
If you want to raise an event from SharePoint you can do a http POST to this new route URL for example
http://localhost:38262/spproxy
It will pass any posted data onto the httphandler below, that will then broadcast it to your clients.
Here is the code for MapHttpHandlerRoute
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace System.Web.Routing
{
public class HttpHandlerRoute : IRouteHandler
{
private String _virtualPath = null;
private IHttpHandler _handler = null;
public HttpHandlerRoute(String virtualPath)
{
_virtualPath = virtualPath;
}
public HttpHandlerRoute(IHttpHandler handler)
{
_handler = handler;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
IHttpHandler result;
if (_handler == null)
{
result = (IHttpHandler)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(_virtualPath, typeof(IHttpHandler));
}
else
{
result = _handler;
}
return result;
}
}
public static class RoutingExtensions
{
public static void MapHttpHandlerRoute(this RouteCollection routes, string routeName, string routeUrl, string physicalFile, RouteValueDictionary defaults = null, RouteValueDictionary constraints = null)
{
var route = new Route(routeUrl, defaults, constraints, new HttpHandlerRoute(physicalFile));
RouteTable.Routes.Add(routeName, route);
}
public static void MapHttpHandlerRoute(this RouteCollection routes, string routeName, string routeUrl, IHttpHandler handler, RouteValueDictionary defaults = null, RouteValueDictionary constraints = null)
{
var route = new Route(routeUrl, defaults, constraints, new HttpHandlerRoute(handler));
RouteTable.Routes.Add(routeName, route);
}
}
}
Or you could just post directly to a httphandler and get the handler to do a connection.Broadcast
namespace SharePointRProxy
{
/// <summary>
/// Summary description for SharePointRProxyHandler
/// </summary>
public class SharePointRProxyHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
IConnectionManager connectonManager = AspNetHost.DependencyResolver.Resolve<IConnectionManager>();
IConnection connection = connectonManager.GetConnection<MyConnection>();
object payload = null; //Add payload here 'context.Request.Params["data"] ?'
JavaScriptSerializer jss = new JavaScriptSerializer();
var payloadJSON = jss.Serialize(payload);
connection.Broadcast(payloadJSON);
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
You could also use either an event handler calling a .net 4.0 web service or an http handler to grab requests from SharePoint and pass them over to a .net 4.0 application running your signalr code.
You can see an example of using an http handler here: http://spmatt.wordpress.com/2012/04/12/harnessing-signalr-in-sharepoint/

Resources