Access in memory dbcontext in integration test - testing

How can I access the dbcontext of an in memory database inside an integration test?
I have followed the code here:
https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2#customize-webapplicationfactory
and have a similar test to:
public class IndexPageTests :
IClassFixture<CustomWebApplicationFactory<RazorPagesProject.Startup>>
{
private readonly HttpClient _client;
private readonly CustomWebApplicationFactory<RazorPagesProject.Startup>
_factory;
public IndexPageTests(
CustomWebApplicationFactory<RazorPagesProject.Startup> factory)
{
_factory = factory;
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
}
In this IndexPageTests is it possible to access the in-memory dbcontext?
I have tried
using (var context = new ApplicationDbContext(???))
I need to access data from tables i had previously seeded from CustomWebApplicationFactory
but not sure what to put for the options

Thanks to Nikosi, this is the way I managed to get the dbcontext
var scopeFactory = _factory.Server.Host.Services.GetService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
}

The below worked with me as it didn't throw an exception:
var scope = factory.Services.GetService<IServiceScopeFactory().CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext();
Ref. https://github.com/dotnet/aspnetcore/issues/14424

Related

Storing and retrieving values from IDistributedCache (Redis) in .NET Core 2

I have an ASP.NET Core2 application. I am using both builtin and Autofac IoC containers. I am setting up all the component registrations in my Startup.cs file. While doing this, I am also setting up my DBContext which inherits from a custom DataContext which in turn inherits from DbContext and implements a custom IDataContextAsync. This DbContext expects a connection string as a constructor parameter.
My problem is that the connection string is stored in the Redis Cache which is an IDistributedCache. The cache is setup in the startup.cs file. The Connection String also is required in the same ConfigureServices method in Startup.cs. So, I don't seem to have access to this cache at this point.
Everything was working when I was using the HttpContext Session to store the connection string. Now that the application is being deployed to a Web farm, I can't use in proc session. We are using Redis for state management. This is where I am having a problem with.
Here is my ConfigureServices method from startup.cs file (unnecessary code removed for brevity).
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddJsonOptions(op => op.SerializerSettings.ContractResolver = new DefaultContractResolver());
services.AddSession(opt =>
{
opt.IdleTimeout = TimeSpan.FromMinutes(20);
opt.Cookie.Name = "apexportal.RulesSession";
opt.Cookie.HttpOnly = true;
});
services.AddDistributedRedisCache(o =>
{
var host = Configuration.GetValue<string>($"{AppConstants.REDIS}:{AppConstants.REDISHOST}");
var port = Configuration.GetValue<string>($"{AppConstants.REDIS}:{AppConstants.REDISPORT}");
o.Configuration = $"{host}";
o.InstanceName = Configuration.GetValue<string>($"{AppConstants.REDIS}:{AppConstants.REDISNAME}");
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//services.AddTransient<IConnectionStringProvider, ConnectionStringProvider>();
services.AddTransient<IDataContextAsync>(s => new PortalEFContext(GetPortalConnectionString()));
services.AddAuthentication(IISDefaults.AuthenticationScheme);
ContainerBuilder builder = new ContainerBuilder();
builder.Populate( services );
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
and here is my GetPortalConnectionString() method which is also in the startup.cs file. I want to replace the line accessor.HttpContext.Session.Get() with an injected RedisCache.Get().
private string GetPortalConnectionString()
{
IHttpContextAccessor accessor = new HttpContextAccessor();
//this is where I need to access the RedisCache and access the stored properties
// instead of using HttpContext.Session. But I don't know how to inject the IDistributedCache
// to this spot.
var connString = accessor.HttpContext.Session.Get<string>(AppConstants.SPCONNSTRING);
return connString ?? Configuration.GetConnectionString("PortalEFContext");
}
Later when the user has selected a database to use in the application, I am storing the connectionstring to that database in Redis Cache like so.
Here is my BaseController class which does that.
public abstract class BaseController : Controller
{
//private readonly IRulesEngineService reService;
protected readonly IHttpContextAccessor httpCtxAccessor;
protected readonly IConfiguration config;
private readonly IAuthService authService;
protected readonly IDistributedCache redisCache;
public BaseController(IHttpContextAccessor _httpContext, IConfiguration _config, IAuthService _authService, IDistributedCache _redisCache)
{
//reService = _reService;
httpCtxAccessor = _httpContext;
config = _config;
authService = _authService;
redisCache = _redisCache;
//SetupCurrentWindowsUserAsync();
}
protected async Task<string> SetCurrentDBConnString( int dbId )
{
var currDbId = await GetCurrentDBId();
if ( currDbId == 0 || currDbId != dbId )
{
var envConnStr = config.GetConnectionString( AppConstants.ENVCONNSTRING );
var connStr = await AppHelper.SetCurrentDBConnectionString( dbId, envConnStr );
//httpCtxAccessor.HttpContext.Session.Set<string>( AppConstants.SPCONNSTRING, connStr );
//httpCtxAccessor.HttpContext.Session.Set<int>( AppConstants.CURRDBID, dbId );
await redisCache.SetAsync<string>( AppConstants.SPCONNSTRING, connStr );
await redisCache.SetAsync<int>( AppConstants.CURRDBID, dbId );
await SetupCurrentWindowsUserAsync();
return connStr;
}
return null;
}
}
Can someone please tell me how I can access the Redis cache in my startup.cs file? Thanks.
It's actually very simple. You were almost there already.
Take a closer look at this line in your startup:
services.AddTransient<IDataContextAsync>(s => new PortalEFContext(GetPortalConnectionString()));
See the s parameter in the lambda? This is the DI container of .NET Core called IServiceProvider. This is what you were looking for. Just pass it down into your function and use it there to resolve anything you want.
So, the code will be the following:
public IServiceProvider ConfigureServices(IServiceCollection services)
...
services.AddTransient<IDataContextAsync>(s => new PortalEFContext(GetPortalConnectionString(s))); // <-- pass the container to the function
...
}
private string GetPortalConnectionString(IServiceProvider container)
{
// Here you go:
var cache = container.GetService<IDistributedCache>();
// and now do whatever you want with it.
var connString = cache.Get<string>(AppConstants.SPCONNSTRING);
// BTW, configuration can be resolved from container as well in order to avoid hard dependency on global Configuration object:
var config = container.GetService<IConfiguration>();
return connString ?? config.GetConnectionString("PortalEFContext");
}

Custom action filter unity dependency injection web api 2

I followed this article and got everything working except dependency inject (partially). In my project I am using unity and I am trying to create a custom Transaction attribute the purpose of which is to start a NHibernate transaction before the execution of an action and commit/rollback the transaction after the method execution.
This is the definition of my attribute:-
public class TransactionAttribute : Attribute
{
}
Following is the definition of my TransactionFilter
public class TransactionFilter : IActionFilter
{
private readonly IUnitOfWork _unitOfWork;
public TransactionFilter(IUnitOfWork uow) {
_unitOfWork = uow;
}
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) {
var transAttribute = actionContext.ActionDescriptor.GetCustomAttributes<TransactionAttribute>().SingleOrDefault();
if (transAttribute == null) {
return continuation();
}
var transaction = uow.BeginTransaction();
return continuation().ContinueWith(t =>
{
try{
transaction.Commit();
return t.Result;
}
catch(Exception e)
{
transaction.Rollback();
return new ExceptionResult(ex, actionContext.ControllerContext.Controller as ApiController).ExecuteAsync(cancellationToken).Result;
}
}
}
}
And I have created a custom filter provider which uses unity to construct this filter.
public class UnityActionFilterProvider
: ActionDescriptorFilterProvider,
IFilterProvider
{
private readonly IUnityContainer container;
public UnityActionFilterProvider(IUnityContainer container)
{
this.container = container;
}
public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
foreach (IActionFilter actionFilter in container.ResolveAll<IActionFilter>())
{
// TODO: Determine correct FilterScope
yield return new FilterInfo(actionFilter, FilterScope.Global);
}
}
}
I register the UnityActionFilterProvider in UnityWebApiActivator (I am using Unity.AspNet.WebApi package) as follows
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
var resolver = new UnityDependencyResolver(container);
var config = GlobalConfiguration.Configuration;
config.DependencyResolver = resolver;
var providers = config.Services.GetFilterProviders();
var defaultProvider = providers.Single(i => i is ActionDescriptorFilterProvider);
config.Services.Remove(typeof(IFilterProvider), defaultProvider);
config.Services.Add(typeof(IFilterProvider), new UnityActionFilterProvider(container));
}
The problem is everything works ok for the first request for any action but subsequent requests for the same action doesn't recreate the TransactionFilter which means it doesn't call the constructor to assign a new UOW. I don't think I can disable the action filter caching.
The only option I have got now is to use the service locator pattern and get UOW instance using container inside ExecuteActionFilterAsync which in my opinion kills the purpose of this and I am better off implementing custom ActionFilterAttribute.
Any suggestions ?
As far as I've been able to tell during the years, what happens in web application startup code essentially has Singleton lifetime. That code only runs once.
This means that there's only a single instance of each of your filters. This is good for performance, but doesn't fit your scenario.
The easiest solution to that problem, although a bit of a leaky abstraction, is to inject an Abstract Factory instead of the dependency itself:
public class TransactionFilter : IActionFilter
{
private readonly IFactory<IUnitOfWork> _unitOfWorkFactory;
public TransactionFilter(IFactory<IUnitOfWork> uowFactory) {
_unitOfWorkFactory = uowFactory;
}
// etc...
Then use the factory in the ExecuteActionFilterAsync method:
var transaction = _unitOfWorkFactory.Create().BeginTransaction();
A more elegant solution, in my opinion, would be to use a Decoraptor that Adapts the TransactionFilter, but the above answer is probably easier to understand.

SignalR : use camel case

I would like to know if there is a way to configure SignalR so that the client functions in the hub return objects using camel case.
Thanks.
Roll your own Conttract resolver like
public class SignalRContractResolver : IContractResolver
{
private readonly Assembly assembly;
private readonly IContractResolver camelCaseContractResolver;
private readonly IContractResolver defaultContractSerializer;
public SignalRContractResolver()
{
defaultContractSerializer = new DefaultContractResolver();
camelCaseContractResolver = new CamelCasePropertyNamesContractResolver();
assembly = typeof(Connection).Assembly;
}
public JsonContract ResolveContract(Type type)
{
if (type.Assembly.Equals(assembly))
{
return defaultContractSerializer.ResolveContract(type);
}
return camelCaseContractResolver.ResolveContract(type);
}
}
Register it like
var settings = new JsonSerializerSettings();
settings.ContractResolver = new SignalRContractResolver();
var serializer = JsonSerializer.Create(settings);
GlobalHost.DependencyResolver.Register(typeof (JsonSerializer), () => serializer);
If you use a custom IoC you can run into problems because JsonSerializer is a concrete type and some IoCs like for example Ninject will inject unbound concrete types. In Ninjects case the solution is to register it with Ninject instead of with SignalRs own DependencyResolver
var settings = new JsonSerializerSettings();
settings.ContractResolver = new SignalRContractResolver();
var serializer = JsonSerializer.Create(settings);
kernel.Bind<JsonSerializer>().ToConstant(serializer);
More info on my blog:
http://andersmalmgren.com/2014/02/27/why-overriding-jsonserializer-no-longer-work-in-signalr-2-0/
Anders answer is correct; I just wanted to add that for anyone using AutoFac instead of Ninject you should use this registration in your startup.cs:
var settings = new JsonSerializerSettings();
settings.ContractResolver = new SignalRContractResolver();
var serializer = JsonSerializer.Create(settings);
builder.RegisterInstance(serializer).As<JsonSerializer>();
Proper way to configure signalR serialization settings for asp.net core is:
// Inside your Startup.ConfigureServices
var settings = new JsonSerializerSettings
{
// ... your serialization settings
};
services.AddOptions<JsonHubProtocolOptions>()
.Configure(x => x.PayloadSerializerSettings = settings);
For use with ASP .NET Core, you can register the JsonSerializer like this in Startup -> ConfigureServices:
var settings = new JsonSerializerSettings { ContractResolver = new SignalRContractResolver() };
var serializer = JsonSerializer.Create(settings);
services.AddSingleton(serializer);
If you don't want to meddling with SignalR config or found it too much hassles, you can add the JsonProperty attribute to specify the property name after serialization on your model. JsonProperty is from JSON.NET, which SignalR uses for serialization.
[JsonProperty("id")]
public byte Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }

Using Ninject with ORMLite

I want to use Ninject with ServiceStack ORMLite but I'm not sure how to configure it.
I have the following in my Repository:
private readonly IDbConnectionFactory _dbFactory;
public TaskRepository(IDbConnectionFactory dbFactory)
{
_dbFactory = dbFactory;
}
public IEnumerable<Task> GetAll()
{
using (IDbConnection _db = _dbFactory.OpenDbConnection())
{
return _db.Select<Task>();
}
}
I'm just not sure how to register it to use my connection string. I have bound OrmLiteConnectionFactory to IDbConnectionFactory like so:
kernel.Bind<IDbConnectionFactory>().To<OrmLiteConnectionFactory>().InScope(x => x.Request);
I have also created a new instance of OrmLiteConnectionFactory in the Configure method in AppHost like so:
var ormLite = new OrmLiteConnectionFactory(
ConfigurationManager.ConnectionStrings["DefaultConnection"]
.ConnectionString, SqlServerDialect.Provider);
But when I try to use a service I get: ConnectionString must be set
Edit
Here is how I have registered OrmLiteConnectionFactory:
Inside Configure I have:
var ormLite = new OrmLiteConnectionFactory(
ConfigurationManager.ConnectionStrings["AngularApp"]
.ConnectionString, SqlServerDialect.Provider);
// Create Tables and Seed Data
CreateSeedData(ormLite);
IKernel kernel = new StandardKernel();
// Register dependencies in method
RegisterDependencies(kernel);
RegisterDependencies looks like:
private void RegisterDependencies(IKernel kernel)
{
kernel.Bind<IDbConnectionFactory>().To<OrmLiteConnectionFactory>()
.InSingletonScope();
kernel.Bind<ITaskRepository>().To<TaskRepository>();
}
IDbConnectionFactory is a db connection factory so it should be a sigleton, i.e. you want to inject the configured instance not create a new one per request, e.g:
kernel.Bind<IDbConnectionFactory>().ToMethod(c =>
new OrmLiteConnectionFactory(
ConfigurationManager.ConnectionStrings["DefaultConnection"]
.ConnectionString, SqlServerDialect.Provider))
.InSingletonScope();

RavenDB- Building Session Factory, singleton DocumentStore

I'm a newbie to RavenDb. I've built the RavenDB session factory like the below code. The idea is very much driven from the way we build NHibernateSessionHelpers. I hope this should work really well in production. Are there any suggestions to improve this from people who are experts in RavenDB?
public class MXRavenDbSessionHelper
{
//---All new lazy singleton that's thread safe.---
private static Lazy<IDocumentStore> _lazyDocStore = new Lazy<IDocumentStore>(() => InitializeSessionFactory());
private MXRavenDbSessionHelper() { }
private static IDocumentStore SessionFactory
{
get
{
return _lazyDocStore.Value;
}
}
public static IDocumentSession OpenSession()
{
return SessionFactory.OpenSession();
}
private static IDocumentStore InitializeSessionFactory()
{
var _docStore = new DocumentStore { ConnectionStringName = "RavenDBConnString", DefaultDatabase = "MXMunky" }; //One more way is this : _store = new DocumentStore { Url = "http://localhost:7000" };
_docStore.Initialize();
_docStore.Conventions.IdentityPartsSeparator = "-";
IndexCreation.CreateIndexes(typeof(Location).Assembly, _docStore);
return _docStore;
}
}
I don't think you need to keep _docStore separately. See Jon Skeet's singleton patterns (#6).
Other than that, I don't see anything particularly wrong with it.
I'd be careful not to use this when unit testing. There, you actually do want a new docstore instance for each test - and they should be disposed properly.