WebApi XController parameterless public constructor required using Heroic.Web.Ioc and Structuremap
johnnycamby opened this issue · comments
What i don't understand is that when implementing DI in an ASP.NET application using an MVC-Controller when using Heroic.Web.Ioc and Structuremap, the above exception(s) is not raised but it's raised when implementing DI in an Api-Controller.
Can you tell me a bit more about the project? Is it is a standard ASP.NET project, or are you self-hosting things? I ask because it looks like the StructureMap dependency resolver isn't being used. When you add the Heroic.Web.IoC package, it adds a StructureMapConfig.cs file to your project, which contains the following assignment:
GlobalConfiguration.Configuration.DependencyResolver = resolver;
Can you verify that there's no where else in your application that's changing out the resolver? If you're self-hosting, you'll need to make sure your self-hosting configuration object's dependency resolver is also populated correctly.
the project is a standard ASP.NET project. I do have added StructureMapConfig.cs that i think only registries MVC controller(s), correct me if i am wrong. And no were else in the application the resolver is being changed. So with a normal mvc-controller DI works but not with an ApiController
The config actually registers both. That's what the GlobalConfiguration.Configuration.DependencyResolver assignment is doing. That line is still in your config file, correct?
Yes
I don't suppose the project is one that you can share the code for, is it?
Matt, earlier on i misinformed you about the project not being self hosted. Its self hosted using OWIN and it seems like i have no clue on how deal with populating my self-hosting configuration object's dependency resolver. any help!
I hope you don't mind me jumping in. In your App_Start\StructureMapConfig.cs are you using:
`cfg.AddRegistry(new ActionFilterRegistry(namespacePrefix: "Your Namespace"));' If XController is custom software, then leave it out. If not, make sure your namespace is accurate, i.e. YourCompany.ProjectName. I would be surprised if XController is 3rd party putting the burden on you to resolve the dependency. At any rate, structuremap used in your application does not know about XController while at the same time it is looking for it. Since it is looking for it, it needs to find it by spinning thru your DLLs, so it needs to check your DLL(s) with the proper namespace, or have it check all DLLs in your bin folder by removing the cfg line of code.
XController is an api controller in a Controllers folder and my namespace is 'AppDemo' . The problem is that i have no proper clue on how to resolver an OWIN Self-hosted application.
App_Start\StructureMapConfig.cs is auto generated.
Ok, for a self-hosted project, somewhere you're probably "new-ing" up an instance of HttpConfiguration. That config object has a DependencyResolver property that you'll need to assign the StructureMap dependency resolver to. It'll probably look something like this:
`
var config = new HttpConfiguration();
config.DependencyResolver = new StructureMapDependencyResolver();
appBuilder.UseWebApi(config);
`
Let me know if that helps.
Matt, you right i had to change my Startup.cs to something like this
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultRouting",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.DependencyResolver = new StructureMapDependencyResolver();
appBuilder.UseWebApi(config);
}
}
which worked, though now i have to solve another issue regarding my Dbcontext being disposed
An error has occurred. The operation cannot be completed because the DbContext has been disposed. System.InvalidOperationException at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() at System.Data.Entity.Internal.Linq.InternalQuery`1.GetEnumerator() at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable.GetEnumerator() at WriteArrayOfMappedDeveloperToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract ) at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Owin.HttpMessageHandlerAdapter.d__13.MoveNext()Sorry for the inconveniences and thanks for the help.
Ahh, that's right, the "container-per-request" that Heroic.Web.IoC implements isn't compatible with OWIN self-hosting yet. It's on my TODO list, but I haven't gotten around to it yet. Because of that, Heroic.Web.IoC won't be much use to you with a self-hosted app. I'll flag this as high-priority, but it will still be a bit before I can get around to implementing that. It's not a trivial change.
thanks for the help.