我在WebApi中遇到DI问题。我已使用instruction相应地添加了autofac。但解决控制器有问题。
我收到错误:
{
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred when trying to create a controller of type 'ValuesController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Type 'WebApiOwinAutoFac.Controllers.ValuesController' does not have a default constructor",
"ExceptionType": "System.ArgumentException",
"StackTrace": " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD WEB API SETUP:
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// builder.RegisterType<ApplicationDbContext>().AsSelf().InstancePerLifetimeScope();
builder.RegisterType<TestRepository>().As<ITestRepository>();
// Run other optional steps, like registering filters,
// per-controller-type services, etc., then set the dependency resolver
// to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// OWIN WEB API SETUP:
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
ConfigureAuth(app);
}
}
ValuesController.cs
[RoutePrefix("api/Values")]
public class ValuesController : ApiController
{
private ITestRepository _context { get; set; }
public ValuesController(ITestRepository context)
{
_context = context;
}
// GET api/values/5
[HttpGet]
public string GetTest()
{
var testList = _context.GetAll();
return String.Join(",", testList.Select(s => s.Name));
}
}
ITestRepository.cs
public interface ITestRepository
{
IEnumerable<TestModel> GetAll();
}
TestRepository.cs
public class TestRepository : ITestRepository
{
private ApplicationDbContext _context = new ApplicationDbContext();
public IEnumerable<TestModel> GetAll()
{
return _context.Tests;
}
}
我尝试使其有效的示例项目可在GitHub上找到: 谢谢你的帮助。
答案 0 :(得分:1)
感谢Travis Illig。我今天也学到了新东西。
您需要两件事 - 删除Global.ascx.cs中的GlobalConfiguration,并使用OWIN注册Web API路径。
[assembly: OwinStartup(typeof(WebApiOwinAutoFac.Startup))]
namespace WebApiOwinAutoFac
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD WEB API SETUP:
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// builder.RegisterType<ApplicationDbContext>().AsSelf().InstancePerLifetimeScope();
builder.RegisterType<TestRepository>().As<ITestRepository>();
// Run other optional steps, like registering filters,
// per-controller-type services, etc., then set the dependency resolver
// to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// OWIN WEB API SETUP:
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
ConfigureAuth(app);
}
}
}
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//GlobalConfiguration.Configure(WebApiConfig.Register); <-- Delete this line
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
答案 1 :(得分:1)
问题是您的示例项目没有使用OWIN。它仍然使用经典的非OWIN ASP.NET Web API。如果您look at your Global.asax.cs,您会发现自己仍在使用GlobalConfiguration
。使用OWIN时无法使用GlobalConfiguration
。
您将在the Autofac docs on Web API and OWIN integration中注意到以下内容:
OWIN集成中的常见错误是使用
GlobalConfiguration.Configuration
。 在OWIN中,您可以从头开始创建配置。使用OWIN集成时,不应在任何地方引用GlobalConfiguration.Configuration
。
从Global.asax中删除GlobalConfiguration
的使用情况,然后完全切换到OWIN。你不能混合搭配,否则你会遇到这样的麻烦。
答案 2 :(得分:0)
您需要告诉WebApi如何创建控制器。我喜欢通过创建组合根来实现。 Mark Seemann有一篇很好的文章here。我的实现看起来像这样。我正在使用StructureMap,但AutoFac将具有类似的设置。在构造函数中,我传递的是IoC容器,在Create
方法中,我使用controllerType
参数从容器中获取控制器的实例。
public class CompositionRoot : IHttpControllerActivator
{
private readonly IContainer _container;
public CompositionRoot(IContainer container)
{
if (container == null) throw new ArgumentNullException(nameof(container));
_container = container;
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = (IHttpController) _container.GetInstance(controllerType);
return controller;
}
你可以在你的startup.cs中连接它(再次使用StructureMap):
config.Services.Replace(typeof (IHttpControllerActivator), new CompositionRoot(container));
这是一个更加手动的连线,这意味着您可能不需要这些线路:
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
希望有所帮助