Simple Injector registration problem in SignalR - c#

I set DI in my Controller as shown below and tied to register IHubContext as it seen on
Controller:
public class DemoController : Controller
{
private IHubContext<DemoHub> context;
public DemoController(IHubContext<DemoHub> context)
{
this.context = context;
}
}
Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.Register<IHubContext, IHubContext>(Lifestyle.Scoped);
// or
container.Register<IHubContext>(Lifestyle.Scoped);
// code omitted
}
But when I debug my app, encounter "System.ArgumentException: 'The given type IHubContext is not a concrete type. Please use one of the other overloads to register this type. Parameter name: TImplementation'" error. So, how can I register IHubContext properly?

Since ASP.NET MVC doesn't have built in dependency injection for SignalR hub context you have to obtain a context instance using GlobalHost.ConnectionManager. With this you can register a dependency with your container that creates IHubContext instance. Considering you have typed hub
public class DemoHub : Hub<ITypedClient>
{
}
and interface
public interface ITypedClient
{
void Test();
}
register dependency as the following
container.Register<IHubContext<ITypedClient>>(() =>
{
return GlobalHost.ConnectionManager.GetHubContext<DemoHub, ITypedClient>();
}, Lifestyle.Scoped);
And the controller should look like
public class DemoController : Controller
{
private IHubContext<ITypedClient> context;
public DemoController(IHubContext<ITypedClient> context)
{
this.context = context;
}
}

Related

How to actually register Signalr's IConnectionManager to Dependency Injection

How to actually register IConnectionManager with some DependencyInjection implementation? (Unfortunely it is not Core)
I tried Autofac and some "manual" way to achieve it, but none of them works for me
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterType<IConnectionManager>().InstancePerRequest();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.MapSignalR();
}
There is no parameterless constructor defined for this object.
How can I then obtain SignalR's IConnectionManager in my controller?
private readonly IHubContext _hubContext;
public HomeController(IConnectionManager hubManager)
{
_hubContext = hubManager.GetHubContext<TestHub>();
}
You need not to inject IConnectionManager to your controller. You can get IConnectionManager from GlobalHost
GlobalHost.ConnectionManager:
Gets the default IConnectionManager.
Try below solution,
public HomeController
{
private static IHubContext HubContext { get; set; };
//Use static constructor, as getting hub context is an expensive operation
public static HomeController()
{
HubContext = GlobalHost.ConnectionManager.GetHubContext<TestHub>();
}
...
}
Note: As getting default IConnectionManger is an expensive task, use static property and static constructor to execute only once in your application.

Unity Dependency Injection only working when injecting into MVC Controller?

I wish to inject a service into a custom class i have created> i have been using Dependency injection to inject the same service into my WebApi controllers but cannot seem to understand why it doesn't work in my "InputDataValidationModel" class
This is what i am trying to do:
public class InputDataValidationModel
{
private ISec300_EE_SubmissionRepository _service { get; set; }
public InputDataValidationModel(ISec300_EE_SubmissionRepository service)
{
_service = service;
}
}
In the Global.asax i registered the types as follow:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ConfigureApi(GlobalConfiguration.Configuration);
}
void ConfigureApi(HttpConfiguration config)
{
var unity = new UnityContainer();
// Register the Controllers that should be injectable
unity.RegisterType<SEC300_EE_SubmissionController>();
unity.RegisterType<InputDataValidationModel>();
unity.RegisterType<ISec300_EE_SubmissionRepository, Sec300_EE_SubmissionRepository>(new ContainerControlledLifetimeManager());
unity.RegisterType<IClientRepository, ClientRepository>(new ContainerControlledLifetimeManager());
// Finally, override the default dependency resolver with Unity
config.DependencyResolver = new IoCContainer(unity);
}
What I cant understand specifically is that this works perfectly when done in my controller below:
public class SEC300_EE_SubmissionController : ApiController
{
private ISec300_EE_SubmissionRepository _service;
public SEC300_EE_SubmissionController(ISec300_EE_SubmissionRepository service)
{
if (service == null)
{
throw new ArgumentNullException("service");
}
_service = service;
}
}
It does not work because controllers are instantiated by Web API, and when Web API creates a controller it calls BeginScope which is the entry point to call your IoC and proceeds to resolve and constructs objects for you.
In your case InputDataValidationModel is not used and may be for this reason you don't have the instance
update
Do you perhaps have any suggestions on how i would inject my service into InputDataValidationModel ?
Option 1
You can use IDependencyResolver take a look at this link Dependency Resolution with the Unity Container`'
And after this you can resolve your service like this
var instance =GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof (InputDataValidationModel));
Option 2
You might use service locator even it is an anti-pattern
static void Main(string[] args)
{
UnityServiceLocator locator = new UnityServiceLocator(ConfigureUnityContainer(
ServiceLocator.SetLocatorProvider(() => locator);
var a = ServiceLocator.Current.GetInstance<IFoo>();
var b = ServiceLocator.Current.GetInstance<IFoo>();
Console.WriteLine(a.Equals(b));
}
private static IUnityContainer ConfigureUnityContainer()
{
UnityContainer container = new UnityContainer();
container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());
return container;
}
Hope this help

Unity DI not working in DI - default controller constructor called instead

I am trying to get Unity Container Dependency Injection working on a self-hosted owin app. I have added the Unity nuget package to my project, and have set up my UnityConfig class as follows:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IDBContext,UniversalCoatingsDbContext>();
container.RegisterType<IUserRepository,UserRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Then, I set up my controller like this:
public class UserController : ApiController
{
private IUserRepository userRepo;
public UserController() {
Console.WriteLine("User controller default constructor");
}
//dependency injected value
public UserController(IUserRepository repo)
{
this.userRepo = repo;
Console.WriteLine("DI enabled constructor");
}
[HttpPost]
public JsonResult<MessageResponse> Register(UnhashedUser unhashed_user)
{
MessageResponse response = new MessageResponse();
if(ModelState.IsValid)
{
response = userRepo.createUser(unhashed_user);
}
else
{
response.message = "Invalid Request sent.";
}
return Json(response);
}
}
The UnityConfig.RegisterComponents() method is called at the end of my Startup class's Configuration() method (after all the middleware is setup). When I access this controller's URL, the parameterless constructor is always called, and thus the instance of IUserRepository is never resolved.
Am I missing some sort of configuration pattern? Any info greatly appreciated.
I modified my UnityConfig class to expose the container as a static variable. And then,
I added this to my startup class:
//set up dependency injection
UnityConfig.RegisterComponents();
config.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(UnityConfig.container);
app.UseWebApi(config);

Autofac with Web Api controller

I'm trying to use Autofac with WebApi controllers. I have :
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
AutofacConfig.Register();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Here is my AutofacConfig:
public class AutofacConfig
{
public static IContainer Container { get; private set; }
public static void Register()
{
var builder = new ContainerBuilder();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
//Register repositories and services.
Container = builder.Build();
}
}
Then I'm trying to set DependencyResolver:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Filters.Add(new ExceptionHandlingAttribute());
var container = AutofacConfig.Container;//I have registered controllers here!!!
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
But during the request I'm receiving : "Make sure that the controller has a parameterless public constructor".
Also I've tried to set the DependencyResolver in the AutofacConfig class, just like in the tutorial
What's wrong with that?
The error message means that your controller has some dependencies that Autofac doesn't know how to inject them for you. In other words, your controller's constructor has some dependencies (parameters) that needs to be injected but those dependencies (services) themselves haven't been registered in Autofac.
If you share your controller's constructor code we would be able to identify those unregistered dependencies for you.

web api self host custom ioc inject data to controllers

I have a property in my web api self hosted app that I would like to inject to my controllers, which is loaded via reflection using my custom IoC framework, here is my startup code:
public CustomClass StuffInstance { get; set; }
// This method is required by Katana:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var webApiConfiguration = ConfigureWebApi();
// Use the extension method provided by the WebApi.Owin library:
app.UseWebApi(webApiConfiguration);
}
my controllers are mostly scaffolded and some like:
// PUT: api/EventTypeDescriptions/5
[ResponseType(typeof(void))]
public IHttpActionResult PutStuff(int id, int something)
{
//do stuff
//here i would like to use StuffInstance like a singleton
return StatusCode(HttpStatusCode.NoContent);
}
how can a inject StuffInstance to my controllers? this information would be relevant to anyone making an IoC framework btw
I found the information to inject instances to my controllers in this link:
http://www.asp.net/web-api/overview/advanced/dependency-injection
basically i implemented a dependency resolver for my custom IoC Library
in case someone has the same problem, here is the code, maybe for other IoC frameworks it needs more work
public class CustomIocDependencyResolver : IDependencyResolver
{
private readonly CustomIoc container;
public ComponentLoaderWebApiDependencyResolver(CustomIoc container)
{
this.container = container;
}
IDependencyScope IDependencyResolver.BeginScope()
{
return new CustomIocDependencyResolver(container);
}
Object IDependencyScope.GetService(Type serviceType)
{
return container.GetInstance(serviceType);
}
IEnumerable<Object> IDependencyScope.GetServices(Type serviceType)
{
return container.GetAllInstances(serviceType);
}
public void Dispose()
{
}
}
now my katana Configuration looks like:
// This method is required by Katana:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var config = ConfigureWebApi();
config.DependencyResolver = CustomIocDependencyResolver(container);
// Use the extension method provided by the WebApi.Owin library:
app.UseWebApi(config);
}
being container the instance of my custom IoC
Since you mentioned AutoFac as a potential candidate, I recommend you follow their tutorial on WebAPI integration. You'll need to define an interface on CustomClass so that you can properly inject it.
You'll need to inject your instance that you've created (since you want to treat it as a singleton) by registering it as an instance component.
public interface ICustomClass {}
public class CustomClass : ICustomClass {}
public CustomClass _stuffInstance = new CustomClass();
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var builder = new ContainerBuilder();
var config = new HttpConfiguration();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterInstance(_stuffInstance).As<ICustomClass>();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
Then, in each controller's constructor, inject your instance that's been bound to the appropriate interface.
public class CustomController : ApiController
{
private readonly ICustomClass _customClass;
public CustomController(ICustomClass customClass)
{
_customClass = customClass;
}
}
With ASP.NET Core 6 you can now register a service provider:
builder.Services.AddScoped<ICustomClass, CustomClass>(sp => new CustomClass()/* or your already existing instance */);
builder.Services.AddSingleton<ICustomClass>(sp => new CustomClass()/* or your already existing singleton instance */);
it will be injected to your controllers:
[Route("api/[controller]")]
[ApiController]
public class MyController : ControllerBase
{
private readonly ICustomClass _customClass;
private readonly ILogger _logger;
public MyController(ICustomClass customClass, ILogger<MyController> logger)
{
_customClass = customClass;
_logger = logger;
}

Categories

Resources