The IControllerFactory 'UnityControllerFactory' did not return a controller for the name 'controller' - asp.net-mvc-4

I have an MVC 5 project and using Unity Framework for Dependency Injection. Everything was working fine but suddenly I am getting below error
"The IControllerFactory 'App.Web.Models.UnityControllerFactory' did not return a controller for the name 'School'."
GLobal.asax.cs code
private static UnityContainer _container;
public static IUnityContainer Container
{
get { return _container; }
}
IUnityContainer IUnityContainerAccessor.Container
{
get { return Container; }
}
#endregion
protected void Application_Start()
{
if (_container == null)
{
_container = new UnityContainer();
ContainerConfig.RegisterTypes(_container);
}
WebApiConfig.Register(GlobalConfiguration.Configuration);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
ContainerConfig.cs
public static class ContainerConfig
{
public static void RegisterTypes(UnityContainer container)
{
container.RegisterInstance<IUnityContainer>(container);
container.RegisterType<Entities>(new HttpContextLifetimeManager<Entities>(), new InjectionConstructor());
container.RegisterType<IDatabaseContext, Entities>();
container.RegisterType<ICommonService, CommonService>();
container.RegisterType<ISearchService, SearchService>();
container.RegisterType<ILogger, Log4NetLogger>();
ControllerBuilder.Current.SetControllerFactory(typeof(UnityControllerFactory));
}
}
UnityControllerFactory.cs
public class UnityControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext context, string controllerName)
{
try
{
var type = GetControllerType(context, controllerName);
if (type == null)
{
throw new InvalidOperationException(string.Format("Could not find a controller with the name {0}.", controllerName));
}
var container = GetContainer(context);
return (IController)container.Resolve(type);
}
catch
{
return null;
}
}
protected virtual IUnityContainer GetContainer(RequestContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var unityContainerAccessor = context.HttpContext.ApplicationInstance as IUnityContainerAccessor;
if (unityContainerAccessor == null)
{
throw new InvalidOperationException("You must extend the HttpApplication in your web project and implement the IContainerAccessor to properly expose your container instance");
}
IUnityContainer container = unityContainerAccessor.Container;
if (container == null)
{
throw new InvalidOperationException("The container seems to be unavailable in your HttpApplication subclass");
}
return container;
}
}
Please help me to resolve this issue. Thanks in advance.

The problem got resolved. I have installed re-sharper tool. And in one of the business class I makes it as abstract. So it was throwing said error.

Related

I can't find IHttpControllerActivator in asp.net core api

I can't find IHttpControllerActivator in asp.net core api
public class WindsorHttpControllerActivator:IHttpControllerActivator
{
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var instance = DependencyContainer.Resolve(controllerType);
if (instance == null)
{
throw new HttpException((int)HttpStatusCode.NotFound, string.Format("{0} cannot be resolved.", controllerType.Name));
}
return (IHttpController) instance;
}
}
Let me know if this rewrite works.
There were changes to the API for third-party DI
using Castle.Windsor;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
public class WindsorControllerActivator : IControllerActivator
{
private readonly IWindsorContainer _container;
public WindsorControllerActivator(IWindsorContainer container)
{
_container = container;
}
public object Create(ControllerContext context)
{
var controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();
var instance = _container.Resolve(controllerType);
if (instance == null)
{
//throw whatever
}
return (ControllerBase)instance;
}
public void Release(ControllerContext context, object controller)
{
_container.Release(controller);
}
}
these articles were helpful to me # least:
https://kristian.hellang.com/third-party-dependency-injection-in-asp-net-core/
https://medium.com/#nevsnirG/manual-controller-activation-and-dependency-injection-in-asp-net-core-web-api-46aba579b0e
EDIT:
in '''Startup.cs''', don't forget the lines
services.AddSingleton<IControllerActivator>(new WindsorControllerActivator (_container));

Modelbinding an optional array of a custom model bound type

I'm stuck with binding an optional array in an ASP.NET Core Controller. The array contains elements of a custom type. Single elements of this type are bound with a custom model binder and validated in it.
Sample repo here: https://github.com/MarcusKohnert/OptionalArrayModelBinding
I get only two tests out of three working in the sample test project:
https://github.com/MarcusKohnert/OptionalArrayModelBinding/blob/master/OptionalArrayModelBindingTest/TestOptionalArrayCustomModelBinder.cs
public class TestOptionalArrayCustomModelBinder
{
private readonly TestServer server;
private readonly HttpClient client;
public TestOptionalArrayCustomModelBinder()
{
server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
client = server.CreateClient();
}
[Fact]
public async Task SuccessWithoutProvidingIds()
{
var response = await client.GetAsync("/api/values");
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
}
[Fact]
public async Task SuccessWithValidIds()
{
var response = await client.GetAsync("/api/values?ids=aaa001&ids=bbb002");
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
}
[Fact]
public async Task FailureWithOneInvalidId()
{
var response = await client.GetAsync("/api/values?ids=xaaa001&ids=bbb002");
Assert.Equal(System.Net.HttpStatusCode.BadRequest, response.StatusCode);
}
}
Controller:
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet]
public IActionResult Get(CustomIdentifier[] ids)
{
if (this.ModelState.IsValid == false) return this.BadRequest();
return this.Ok(ids);
}
}
Startup:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.ModelBinderProviders.Insert(0, new CutomIdentifierModelBinderProvider());
//options.ModelBinderProviders.Add(new CutomIdentifierModelBinderProvider());
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
ModelBinder:
public class CutomIdentifierModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
//if (context.Metadata.ModelType.IsArray && context.Metadata.ModelType == typeof(CustomIdentifier[]))
//{
// return new ArrayModelBinder<CustomIdentifier>(new CustomIdentifierModelBinder());
//}
if (context.Metadata.ModelType == typeof(CustomIdentifier))
{
return new BinderTypeModelBinder(typeof(CustomIdentifierModelBinder));
}
return null;
}
}
public class CustomIdentifierModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var attemptedValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();
var parseResult = CustomIdentifier.TryParse(attemptedValue);
if (parseResult.Failed)
{
bindingContext.Result = ModelBindingResult.Failed();
bindingContext.ModelState.AddModelError(bindingContext.ModelName, parseResult.Message.Message);
}
else
{
bindingContext.Model = parseResult.Value;
bindingContext.Result = ModelBindingResult.Success(parseResult.Value);
}
return Task.CompletedTask;
}
}
The MVC default ArrayModelBinder of T binds optional arrays correctly and sets ModelState.IsValid to true. If I use my own CustomIdentifierModelBinder however ModelState.IsValid will be false. Empty arrays are not recognized as valid.
How can I solve this problem? Thanks in advance.
You are very close. Just customize behavior of built-in ArrayModelBinder for the case of missing parameter. If extracted value is an empty string just fill the model with an empty array. In all other cases you could call usual ArrayModelBinder.
Here is a working sample that passes all your 3 tests:
public class CutomIdentifierModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType.IsArray && context.Metadata.ModelType == typeof(CustomIdentifier[]))
{
return new CustomArrayModelBinder<CustomIdentifier>(new CustomIdentifierModelBinder());
}
return null;
}
}
public class CustomArrayModelBinder<T> : IModelBinder
{
private readonly ArrayModelBinder<T> innerModelBinder;
public CustomArrayModelBinder(IModelBinder elemeBinder)
{
innerModelBinder = new ArrayModelBinder<T>(elemeBinder);
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var attemptedValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();
if (String.IsNullOrEmpty(attemptedValue))
{
bindingContext.Model = new T[0];
bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
return Task.CompletedTask;
}
return innerModelBinder.BindModelAsync(bindingContext);
}
}
The solution is the following code change, reflected in this commit:
https://github.com/MarcusKohnert/OptionalArrayModelBinding/commit/552f4d35d8c33c002e1aa0c05acb407f1f962102
I've found the solution by inspecting MVC's source code again.
https://github.com/aspnet/Mvc/blob/35601f95b345d0ef938fb21ce1c51f5a67a1fb62/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/SimpleTypeModelBinder.cs#L37
You'll need to check the valueProviderResult for None. If it's none then there is no parameter given and the ModelBinder binds correctly.
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == ValueProviderResult.None)
And also you register the provided ArrayModelBinder of T with your custom ModelBinder:
if (context.Metadata.ModelType.IsArray && context.Metadata.ModelType == typeof(CustomIdentifier[]))
{
return new ArrayModelBinder<CustomIdentifier>(new CustomIdentifierModelBinder());
}

Injecting Dependency into Web API Controller

I want to inject unity container into WebController.
I have UnityDependencyResolver:
public class UnityDependencyResolver : IDependencyResolver
{
readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
this._container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch
{
return new List<object>();
}
}
public void Dispose()
{
_container.Dispose();
}
}
Then, in my Global.asax I add the following line:
var container = new UnityContainer();
container.RegisterType<IService, Service>
(new PerThreadLifetimeManager()).RegisterType<IDALContext, DALContext>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Then, If I use the following in a Web Controller:
private IService _service;
public HomeController(IService srv)
{
_service = srv;
}
It works fine.
But I want to inject it into WebAPI Controller, so if I do it the same way:
private IService _service;
public ValuesController(IService srv)
{
_service = srv;
}
It does not work, it says that constructor is not defined.
Ok, I create one more constructor:
public ValuesController(){}
And in this case it uses only this constructor and never the one where I should inject unity container.
Please advise.
Add this in your WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Routes and other stuff here...
var container = IocContainer.Instance; // Or any other way to fetch your container.
config.DependencyResolver = new UnityDependencyResolver(container);
}
}
And if you want the same container you can keep it in a static variable, like so:
public static class IocContainer
{
private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
return container;
});
public static IUnityContainer Instance
{
get { return Container.Value; }
}
}
More info can be found here:
http://www.asp.net/web-api/overview/advanced/dependency-injection
On a sidenote, I can also recommend the nuget-package Unity.Mvc. It adds a UnityWebActivator and support for PerRequestLifetimeManager.
https://www.nuget.org/packages/Unity.Mvc/

Routing Error with WebApi 2, Castle Windsor, Glass mapper

I have setup Castle Windsor and WebApi after reading about it in the below 2 posts. Here is my a highlight of my setup:
Reference Posts:
How do I get Web API / Castle Windsor to recognize a Controller?
Dependency Injection in WebAPI with Castle Windsor
Code Setup:
public static class GlassMapperScCustom
{
public static void CastleConfig(IWindsorContainer container)
{
container.AddFacility<TypedFactoryFacility>();
var config = new Config
{
UseWindsorContructor = true
};
//MVC
container.Register(Component.For<SitecoreController>().LifestyleTransient());
container.Register(Types.FromThisAssembly().BasedOn<Controller>().LifestyleTransient());
DependencyResolver.SetResolver(new WindsorMvcDependencyResolver(container));
ControllerBuilder.Current.SetControllerFactory(new WindsorMvcControllerFactory(container.Kernel));
//WebApiInstaller
container.Register(Types.FromThisAssembly().BasedOn<ApiController>().LifestyleTransient());
var resolver = new WindsorResolver(container); //Shown Below
GlobalConfiguration.Configuration.DependencyResolver = resolver;
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorWebApiControllerActivator(resolver));
}
}
public class WindsorMvcDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorMvcDependencyResolver(IWindsorContainer container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public object GetService(Type serviceType)
{
return _container.Kernel.HasComponent(serviceType) ? _container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.ResolveAll(serviceType).Cast<object>().ToArray();
}
}
public class WindsorMvcControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorMvcControllerFactory(IKernel kernel)
{
this._kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.",
requestContext.HttpContext.Request.Path));
}
return (IController)_kernel.Resolve(controllerType);
}
}
internal class WindsorResolver : IDependencyResolver, IDependencyScope, IDisposable
{
private readonly IWindsorContainer _container;
public WindsorResolver(IWindsorContainer container)
{
this._container = container;
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(this._container);
}
public void Dispose()
{
this._container.Dispose();
}
public object GetService(Type serviceType)
{
if (!this._container.Kernel.HasComponent(serviceType))
return (object)null;
else
return this._container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (!this._container.Kernel.HasComponent(serviceType))
return (IEnumerable<object>)new object[0];
else
return Enumerable.Cast<object>((IEnumerable)this._container.ResolveAll(serviceType));
}
}
public class WindsorWebApiControllerActivator : IHttpControllerActivator
{
private readonly IDependencyResolver _container;
public WindsorWebApiControllerActivator(IDependencyResolver container)
{
_container = container;
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var scope = _container.BeginScope();
var controller = (IHttpController)scope.GetService(controllerType);
request.RegisterForDispose(scope);
return controller;
}
}
//WebApiConfig.cs
public static class WebApiConfig
{
public static void Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
public static void Register(HttpConfiguration config)
{
// initialize and map all attribute routed Web API controllers (note: this does not enable MVC attribute routing)
config.MapHttpAttributeRoutes();
config.EnsureInitialized();
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new {id = RouteParameter.Optional});
// force JSON responses only (no XML)
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
}
}
//Global.asax.cs
public class MvcApplication : Sitecore.Web.Application
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
If I add a test ApiController and try to go to '/api/Test' it gives me a 404 everytime. I used RouteDebugger to view whats wrong and I get the below error everytime:
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
public string Get(int id)
{
return "value";
}
I am not sure where "api/sitecore" is coming from. I followed the instructions on [WebApi2 Attribute Routing with Sitecore][1] post as well but unable to get it working. Can someone point me to what I am doing wrong?
Sitecore is using /api/ as its default route URL.
Rename your controller to something else than ApiController or change Sitecore's default route in the Global.asax and web.config
From a quick glance it
looks like there are no routes registered. The only route in WebApiConfig is commented out.

Signalr + unity DI

I have used Signalr in my MVC4 project succesfully by the conventional method by setting up a normal hub, including the JS file /signalr/hubs and it works.
Now I am trying to setup DI with unity:
In Global.asax
UnityContainer = Bootstrapper.Initialise();
var unityDependencyResolver = new UnityDependencyResolver(UnityContainer);
// Used for MVC
DependencyResolver.SetResolver(unityDependencyResolver);
// Used for SignalR
GlobalHost.DependencyResolver = new SignalRUnityDependencyResolver(UnityContainer);
RouteTable.Routes.MapHubs();
Bootstrapper.cs
public static IUnityContainer Initialise()
{
var unityContainer = new UnityContainer();
unityContainer.RegisterType<IUsers, Users>();
unityContainer.RegisterType<ChatHub>(new InjectionFactory(CreateMyHub));
return unityContainer;
}
private static object CreateMyHub(IUnityContainer p)
{
return new ChatHub(p.Resolve<IUsers>());
}
And the hub:
public class UserHub : Hub
{
private readonly IUsers _users;
public ChatHub(IUsers users)
{
_users = users;
}
public void Send(String message)
{
Clients.All.addMessage(message);
}
}
My SignalRUnityDependencyResolver.cs
public class SignalRUnityDependencyResolver : DefaultDependencyResolver
{
private readonly IUnityContainer _container;
public SignalRUnityDependencyResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container", "Containet cannot be null");
}
_container = container;
}
public override Object GetService(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.Resolve(serviceType) : base.GetService(serviceType);
}
public override IEnumerable<Object> GetServices(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.ResolveAll(serviceType) : base.GetServices(serviceType);
}
}
This is working for non hubs because all dependencies resolve, but now the javascript file <script src="~/signalr/hubs"></script> is not generated anymore.
How can I debug this generation of JS and where could be the culprit?
you can use this in config
EnableJavaScriptProxies = false
the code like this:
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true,
EnableJavaScriptProxies = false
};
map.RunSignalR(hubConfiguration);
});