Castle Windsor throws 'Scope cache was already disposed.' in SignalR Hubs - signalr

We are developing a web application based on
.NET 4.5.1
MVC 5.2.2
OWIN
WebApi 2.2
SignalR 2.2.0
Castle.Windsor 3.3.0
Wcf Integration Facility 3.3.0
For resolving the controllers we use ControllerFactory class which was described in the page below:
http://docs.castleproject.org/Windsor.Windsor-tutorial-part-two-plugging-Windsor-in.ashx
For resolving the dependencies we use WindsorDependencyResolver class:
public class WindsorDependencyResolver : IDependencyResolver
{
public IWindsorContainer Container { get; private set; }
public WindsorDependencyResolver(IWindsorContainer windsorContainer)
{
Container = windsorContainer;
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(this.Container);
}
public object GetService(Type serviceType)
{
return this.Container.Kernel.HasComponent(serviceType) ? this.Container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.Container.ResolveAll(serviceType).Cast<object>().ToArray();
}
public void Dispose()
{
}
}
public class WindsorDependencyScope : IDependencyScope
{
public IWindsorContainer Container { get; set; }
public IDisposable Scope { get; set; }
public WindsorDependencyScope(IWindsorContainer container)
{
this.Container = container;
this.Scope = container.BeginScope();
}
public object GetService(Type serviceType)
{
return this.Container.Kernel.HasComponent(serviceType) ? this.Container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.Container.ResolveAll(serviceType).Cast<object>().ToArray();
}
public void Dispose()
{
this.Scope.Dispose();
}
}
Keep in mind we don't resolve the IHub classes of SignalR with Windsor container, they are instantiated by OWIN system in pipeline. The Startup.cs code is shown below:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.MapSignalR();
}
}
All of the controllers, wcf service clients and interceptors -excepting logging classes- are registered with LifestylePerWebRequest in the project. However the classes we use for logging are singleton.
There is a setting in the Web.config below:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
...
<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor" />
...
</modules>
</system.webServer>
So when we try to resolve a wcf client -which has per web request lifestyle- in the SignalR hub we get the exception below:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'Scope cache was already disposed. This is most likely a bug in the calling code.'.
at Castle.MicroKernel.Lifestyle.Scoped.ScopeCache.get_Item(Object id)
at Castle.MicroKernel.Lifestyle.Scoped.DefaultLifetimeScope.GetCachedInstance(ComponentModel model, ScopedInstanceActivationCallback createInstance)
at Castle.MicroKernel.Lifestyle.ScopedLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy)
at Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, Boolean requiresDecommission, Boolean instanceRequired, Burden& burden)
at Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, Boolean instanceRequired)
at Castle.MicroKernel.Handlers.AbstractHandler.Resolve(CreationContext context)
at Castle.MicroKernel.DefaultKernel.ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments, IReleasePolicy policy)
at Castle.MicroKernel.DefaultKernel.Castle.MicroKernel.IKernelInternal.Resolve(Type service, IDictionary arguments, IReleasePolicy policy)
at Castle.MicroKernel.DefaultKernel.Resolve(Type service, IDictionary arguments)
at Castle.Windsor.WindsorContainer.Resolve[T]()
at UIServer.WebUI.Hubs.MailThreadHub.Broadcast(MailMessageListDto mailMessage) in c:\Development\DDD\UIServer.WebUI\Hubs\MailThreadHub.cs:line 92
I can see HttpContext in debugger window before the call Container.Resolve() method. I can resolve the singleton logging classes by the way.
The interesting point is my teammate doesn't get any exception. The main difference is our OS versions. I run the code in windows 8.1 and my teammate runs it in windows 7.
We get this exception for only signalr hubs. We don't get any exception in any other place. How can we solve this problem?

I use ServiceLocator for resolve IDependencyResolver in the Startup class. It is look like:
internal class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute("ActionApi", "{controller}/{action}/{id}", new {id = RouteParameter.Optional});
config.DependencyResolver = ServiceLocator.Instance.Resolve<IDependencyResolver>();
appBuilder.UseWebApi(config);
}
}
Maybe it is help.

Related

ASP .NET Core Publish Errors AddDbContext

i actually dont know deploy IIS for LAN server. We are working on this project together with my friend. We share same Wifi. So we want shared api project. Because i working on backend (API-DAL-BLL) layers, my friends working on FrontEnd. But i cant deploy very well.
First my publish cant see my DBContext.So i added Startup addDbContext.
My Startup.cs like this
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<GastroDB>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IMainCategoryService, MainCategoryService>();
}
My Program.cs like this
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).UseUrls("myIpAdress:80").UseIISIntegration().UseStartup<Startup>();
});
}
But iis can not get start. This is my errors ;
.Net Runtime:
Description: The process was terminated due to an unhandled exception.
Exception Info: System.ArgumentException: 'AddDbContext' was called with configuration, but the context type 'GastroDB' only declares a parameterless constructor. This means that the configuration passed to 'AddDbContext' will never be used. If configuration is passed to 'AddDbContext', then 'GastroDB' should declare a constructor that accepts a DbContextOptions<GastroDB> and must pass it to the base constructor for DbContext.
2)IIS AspNetCore Module V2
Application '/LM/W3SVC/1/ROOT' with physical root 'C:\Users\Tuğçe\Desktop\almanya projesi BE\EcommerceGastro.API\bin\Release\net5.0\publish\' hit unexpected managed exception, exception code = '0xe0434352'. First 30KB characters of captured stdout and stderr logs:
Unhandled exception. System.ArgumentException: 'AddDbContext' was called with configuration, but the context type 'GastroDB' only declares a parameterless constructor. This means that the configuration passed to 'AddDbContext' will never be used. If configuration is passed to 'AddDbContext', then 'GastroDB' should declare a constructor that accepts a DbContextOptions<GastroDB> and must pass it to the base constructor for DbContext.
I understand i will shoul add my context constructor like this
public GastroDB(DbContextOptions<GastroDB> options):base(options){}
But i cant add because first start like that on DBContext:
public class GastroDB : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("server=.; database=GastroDB; user id=sa; password=123;");
}
private static GastroDB _dbInstance;
public static GastroDB DBInstance
{
get
{
if (_dbInstance == null)
{
_dbInstance = new GastroDB();
}
return _dbInstance;
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new MyMap());
...
}
public DbSet<MyClass> MyClass{ get; set; }
....
}
}
If i add ctor on this code, my some services throw exeption because i use like this
using (var transaction = new GastroDB())
{
var productList = transaction.Set<DBProduct>().Include(x => x.ProductImage).ToList();
return this.mapper.Map<List<Product>>(productList);
}
How can i fix this problems i dont know how. Please help me
You Should create a constructor that accept
DbContextOptions<GastroDB>.
You don't need to use public static GastroDB DBInstance because
DbContext are registerd as Scoped life time.
public class GastroDB : DbContext
{
public GastroDB(DbContextOptions<GastroDB> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("server=.; database=GastroDB; user id=sa; password=123;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new MyMap());
...
}
public DbSet<MyClass> MyClass{ get; set; }
....
}
}
3 . If you want your DbContext register as singleton lifetime you can use below code instead of create a static property in DbContext
services.AddDbContext<GastroDB>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
}, ServiceLifetime.Singleton);

Controller cannot reach Controller in other project because of constructor ASP:NET Core

I'm new to ASP.NET Core and I'm trying to solve this problem for a week now.
I have a solution with two projects.
And when I start the porject the browser just says:
InvalidOperationException: Unable to resolve service for type 'TSM_Programm.Data.TSMContext' while attempting to activate 'TSM_Programm.Controllers.ResourcesController'.
The first part of the solution is my API-Layer that passes data to a user (currently via postman).
The second project is my Data Access Layer.
This Layer contains several Controllers, all of them using the same constructor, which is the following:
public TSMContext _context;
public ResourcesController(TSMContext context)
{
_context = context;
}
The TSMContext Class is the following:
namespace TSM_Programm.Data
{
public class TSMContext : DbContext
{
public TSMContext(DbContextOptions<TSMContext> options)
: base(options)
{
}
public DbSet<Resource> Resources { get; set; }
public DbSet<Parameter> Parameters { get; set; }
public DbSet<ResourceToParameter> ResourceToParameters { get; set; }
public DbSet<Reservation> Reservations { get; set; }
}
So far so god, but when I am trying to start the program the controllerof the API-Layer does not seem to be able to handle the constructor.
This is my API-Conrtoller:
namespace TSM_API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class APIController : ControllerBase //Base Class without View Support
{
//Troublemaker
public ResourcesController _resources;
public ParametersController _parameters;
public ReservationsController _reservations;
public APIController(ResourcesController resources, ParametersController parameters, ReservationsController reservations)
{
_resources = resources;
_parameters = parameters;
_reservations = reservations;
}
//Function to check if controller works
//GET: api/API
[HttpGet]
public IEnumerable<string> Get()
{
// ResourcesController controller = new ResourcesController();
return new string[] { "value1", "value2" };
}
The API-Controller was not able to use its own constructors, that's why I changed the Startup.cs.
namespace TSM_API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMvc().AddApplicationPart(typeof(ResourcesController).Assembly).AddControllersAsServices();
services.AddMvc().AddApplicationPart(typeof(ParametersController).Assembly).AddControllersAsServices();
services.AddMvc().AddApplicationPart(typeof(ReservationsController).Assembly).AddControllersAsServices();
services.AddMvc().AddApplicationPart(typeof(TSMContext).Assembly).AddControllersAsServices();
}
I'm simply out of ideas on how to solve the problem, since I can't add the TSMContext class a service.
Any idea how to solve it?
Thank you.
I see you have not registered your dbcontext as a dependency injection. Your issue might be due to ResourceController trying to access _context as a DI but it is not registered. To use the context as a dependency injection, register it in the startup.cs as following.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TSMContext>(options => options.UseSqlServer(Configuration.GetConnectionString("YOUR_CONNECTION_STRING")));
//If you have any services that should be used as DI, then they also must be registered as like this
services.AddScoped<Interface, Class>(); //Interface refer to the service interface while class is the actual service you will use.
}

How to correctly use dependency Injection with .Net Core SignalR

I'm learning .Net Core SignalR and investigating how I could use it with my app live charts. I play with some examples on the net and they all work, but I don't know how to use SignalR with database polling. I'm getting below error:
Cannot access a disposed object ...
I'm assuming it is related to my contex is being disposed after request is completed. I'm using dependency injection.
ChatController
public class ChatController : ControllerBase
{
private IChatService _chatService;
private IChatContext<ChatHub> _hub;
public ChatController(IChatContext<ChatHub> hub, IChatService chatService)
{
_hub = hub;
_chatService = chatService;
}
public IActionResult Get()
{
var timerManager = new TimerManager(() => _hub.Clients.All.SendAsync("transferchatdata", _chatService.ChatDataByProds()));
return Ok(new { Message = "Request Completed" });
}
}
ChatService
public interface IChatService
{
IEnumerable<ChatDataByProd> ChatDataByProds();
}
public class ChatService : IChatService
{
private ChatContext _context;
public ChatService(ChatContext context)
{
_context = context;
}
public IEnumerable<ChatDataByProd> ChatDataByProds()
{
return _context.ChatDataByProds;
}
}
ChatHub
public class ChatHub : Hub
{
}
It seems that you are using a EF Core context that is a scoped lifetime service, which means per-request lifetime in ASP.NET Core. Your ChatService must have a longer lifetime than a HTTP request, and a single instance of the database context would be disposed by the container while you are still holding the reference to it.
Thus, you need to obtain an IServiceProvider container in the ctor of ChatService, and GetService the database context each time when you need to access the database.

EF Core DbContext sql connection string error (Tried Following info in MS Docs)

I have a .net Core application and I've been attempting to read from my local instance of SQL Server (2014) with Windows Authentication and continue to run into a repeat error about my connection string. I've been reviewing the MSDN docs as well as connectionstrings.com and thought I had everything configured correctly.
This is my error:
"System.ArgumentException: 'Format of the initialization string does
not conform to specification starting at index 0.'"
Which I take to mean the very start of my connection string.
I have read the other posts related to this exact issue but haven't been able to use them to find a solution.
Here is what I attempt when the error occurs:
public class HomeController : Controller
{
private ModelContext _context;
public HomeController()
{}
public IActionResult Index()
{
var viewModel = new HomeViewModel();
var optionsBuilder = new DbContextOptionsBuilder<ModelContext>();
optionsBuilder.UseSqlServer("DefaultConnection");
using (_context = new ModelContext(optionsBuilder.Options))
{
>>>>>> viewModel.List = _context.TableName.ToList(); <<<<<<<<
I have the following in my "appsettings.json" file:
"ConnectionStrings": {
"DefaultConnection": "Server=MyComputerName; Database=DBName; IntegratedSecurity=SSPI;"
},
In my "ModelContext.cs" file
public class ModelContext : DbContext
{
public ModelContext(DbContextOptions<ModelContext> options)
:base(options)
{ }
[<Table Properties>]
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("DefaultConnection");
}
And "Startup.cs" file:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<ModelContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
Thanks for taking a look!
After much contemplation and re-review of the MS Documents site for EF Core DbContext, I found that I was attempting to implement ALL 3 methods of DbContext configuration: Constructor Argument, OnConfiguring, and dependency injection.
Decided to go with OnConfiguring to get the app moving.

ASP.NET Identity. Register UserManager with Autofac

I have a webapi project where I use Autofac for dependency injection. The problem is that I can't figure out how to register UserManager class. It's throwing the error "{The entity type ApplicationUser is not part of the model for the current context.} System.InvalidOperationException".
Please help.
In AutofacConfig.Configure():
builder.RegisterType<ApplicationDbContext>().As<IApplicationDbContext>().InstancePerRequest()
builder.RegisterType<UserManager<ApplicationUser>>().InstancePerRequest();
builder.RegisterType<UserStore<ApplicationUser>>().As<IUserStore<ApplicationUser>>().InstancePerRequest();
And that's how I use it:
public class UsersRepository : IUsersRepository<ApplicationUser>
{
public IApplicationDbContext DbInstance { get; }
private UserManager<ApplicationUser> _userManager;
private IUserStore<ApplicationUser> _userStore;
public UsersRepository(IApplicationDbContext dbInstance, UserManager<ApplicationUser> userManager, IUserStore<ApplicationUser> userStore)
{
DbInstance = dbInstance;
_userManager = userManager;
_userStore = userStore;
}
public void Create(ApplicationUser user)
{
_userManager.Create(user);
DbInstance.SaveChanges();
}
}
IUsersRepository:
public interface IUsersRepository<T> where T : class
{
IApplicationDbContext DbInstance { get; }
void Create(T model);
void Update(string id, T model);
void Delete(string id);
List<T> GetAll();
T Get(string id);
}
I tried this solution: https://gist.github.com/danielok/9271691 but then I have another error when making first call to users webapi controller "ApplicationDbContext is not registered."
Message:
The requested service 'ToDoApp_Data.DbContext.ApplicationDbContext' has not been registered. To avoid this exception, either register a component to provide
the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Stack Trace:
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
at ToDoApp_Api.App_Start.AutofacConfig.<>c.<RegisterOthers>b__4_1(ParameterInfo pi, IComponentContext ctx) in D:\Dev\ToDoApp_Backend\ToDoApp_Api\App_Start\AutofacConfig.cs:line 58
at Autofac.Core.ResolvedParameter.<>c__DisplayClass3_0.<CanSupplyValue>b__0()
at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()
at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
P.S. I think will useful to tell that I have other webapi controllers that I managed to make them work with autofac, but considering that before using DI it was instantiated as follow: UserManager _userManager = new UserManager(new UserStore(new ApplicationDbContext())); . I don't know how to register it.

Resources