Reputation: 93434
Can anyone explain what i'm missing here? I've created a simple application, using the default asp.net core 1.1 MVC template. I'm using the default DI container, and have made no other changes than to add a middleware class, and DI configuration.
The problem is that when using either Scoped or Singleton instances of an object, the same object is not being injected in both places.
Here's the code:
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext, MyInstance myInstance)
{
httpContext.Items["myInstance"] = myInstance;
myInstance.MyProperty = 99;
await _next(httpContext);
}
}
public class MyInstance
{
public int MyProperty { get; set; }
}
In ConfigureServices I have:
services.AddSingleton<MyInstance>();
In Configure I have:
app.UseMiddleware<MyMiddleware>();
And in the Home Controller Index method I have:
public IActionResult Index(MyInstance myInstance)
{
if (ReferenceEquals(HttpContext.Items["myInstance"], myInstance))
Debug.WriteLine("Equal!");
else
Debug.WriteLine("Not Equal!");
return View();
}
Regardless of whether I use Scoped or Singleton lifetimes, this always prints "Not Equal!". In addition, through debugging, I've verified that MyProperty
on MyInstance
is 0 in the HomeController Index.
Clearly, I'm missing something here. It does the same thing in .NET Core 2.0 Preview1 as well.
Any suggestions here?
EDIT:
As another test, I set MyProperty
to a different value in HomeControll/Index and on the second refresh the value was back to 0 again, so obviously it seems to be creating a new transient instance every time.
Upvotes: 4
Views: 5100
Reputation: 93434
Ok, yes. I was missing something. Lol.
I will leave this as a cautionary tale, and because I learned a few things.
First, I was stupidly providing the instance only to UseSingletion, I should have been mapping the interface to the instance. But still, that wasn't necessarily part of the problem. Just something I should have been doing.
Second, I was passing IMyInstance to the Index method, which was being treated as a model bound object, and not injected. I needed to inject in a constructor, which I should have noticed, but did not.
Once I fixed these problems, everything was working correctly.
Oh, what I learned was that MVC does not inject into action methods, however it does inject into other kinds of methods (like Middleware Invoke).
I think the surprising part was that the model binder actually instanced up a MyInstance when nothing was bound to it. I seem to recall that the MVC model binder would only instantiate an object if at least one of its properties was present in the FormsCollection.
If I had actually used the Interface mapping method, the problem would have become instantly obvious, since it would have generated a model binding error about the interface. Thus, the cautionary tale.
Upvotes: 1