how to use auto migration in entity framework core 2 - asp.net-core

I use entity framework core 2. I saw posts in stack-overflow but I can't resolve my problem.
I want to use auto migration in my project without console command.

Try this code:
using (var serviceScope = _scopeFactory.CreateScope())
{
using (var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>())
{
context.Database.Migrate();
}
}
Complete code:
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
host.Services.InitializeDb();
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{//Add Code }
}
}
public interface IDbInitializer
{
void Initialize();
}
public class DbInitializer : IDbInitializer
{
private readonly IServiceScopeFactory _scopeFactory;
public DbInitializer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void Initialize()
{
using (var serviceScope = _scopeFactory.CreateScope())
{
using (var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>())
{
context.Database.Migrate();
}
}
}
}
public static class DbContextOptionsExtensions
{
public static void InitializeDb(this IServiceProvider serviceProvider)
{
var scopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var dbInitialize = scope.ServiceProvider.GetRequiredService<IDbInitializer>();
dbInitialize.Initialize();
}
}
}

Related

Endpoint is null when accessed in middleware during asp.net core 3.1 integration test

I run integration tests for my asp.net core application, the call passes from multiple middle-wares but stops at one of them which has the following line :
var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint;
var attribute = endpoint?.Metadata.GetMetadata<AllowAHeader>();
The endpoint is null.
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup>
where TStartup : class
{
protected override IHostBuilder CreateHostBuilder()
{
var builder = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(x =>
{
x.UseStartup<TStartup>().UseTestServer();
});
return builder;
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
builder.ConfigureTestServices(services =>
{
services.RemoveAll<DbContext>();
services.RemoveAll<DbContextOptions>();
foreach (var option in services.Where(s =>
s.ServiceType.BaseType ==
typeof(DbContextOptions)).ToList())
{
services.Remove(option);
}
services.AddDbContext<DbContext>(options =>
{
options.UseInMemoryDatabase("Testing");
});
});
}
}
Here is the test
public class ClientTests : IClassFixture<CustomWebApplicationFactory<TestStartup>>
{
private readonly HttpClient _client;
public ClientTests(CustomWebApplicationFactory<TestStartup> customWebApplicationFactory)
{
_client = customWebApplicationFactory.CreateClient();
}
[Fact]
public async Task GetClients()
{
_client.DefaultRequestHeaders.Add("X-Integration-Testing", "True");
_client.DefaultRequestHeaders.Add("X-Integration-Authroize", "Basic");
var result = await _client.PostAsync("v1/client", null);
}
}
The TestStartup :
public class TestStartup : Startup
{
public TestStartup(IConfiguration configuration)
: base(configuration)
{
}
protected override void ConfigureMiddlewareForIntegrationTest(IApplicationBuilder app)
{
app.UseMiddleware<AuthenticatedTestRequestMiddleware>();
}
}
public class AuthenticatedTestRequestMiddleware
{
public const string TestingHeader = "X-Integration-Testing";
public const string TestingHeaderAuthValueValue = "X-Integration-Authroize";
private readonly RequestDelegate _next;
public AuthenticatedTestRequestMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.Keys.Contains(TestingHeader))
{
if (context.Request.Headers.Keys.Contains(TestingHeaderAuthValueValue))
{
var encoded = "Basic " + System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes("user" + ":" + "123456"));
context.Request.Headers.Add("Authorization", encoded);
}
}
}
}
In ConfigureWebHostDefaults add:
x.UseHttpSys(opt =>
opt.RequestQueueMode = RequestQueueMode.Create;
)
Have not figured out exactly why it's needed, but I'm guessing it's a bug being the value of RequestQueueMode is 0 by default, same as RequestQueueMode.Create's value.

.Net Core use new ApplicationBuilder instead of IApplicationBuilder from configure

I am attempting to create a "registry" so that just creating a new class implementing IServiceCollectionInitializer or IApplicationBuilderInitializer allows it to be loaded. Instead of having a giant start up class the registry would add those automatically.
My problem is I dont know how to make the app either use a new application builder or retrieve the the one given automatically without getting it from startup.
public class ServiceCollectionInitializerRegistry
{
private readonly IList<IServiceCollectionInitializer> _serviceCollectionInitializers;
private readonly IServiceCollection _serviceCollection;
private readonly IServiceProvider _serviceProvider;
public ServiceCollectionInitializerRegistry(IServiceCollection serviceCollection)
{
_serviceCollectionInitializers = new List<IServiceCollectionInitializer>();
_serviceCollection = serviceCollection;
_serviceProvider = serviceCollection.BuildServiceProvider();
}
public ServiceCollectionInitializerRegistry WithInitializers(
params IServiceCollectionInitializer[] initializers)
{
if (!initializers.Any())
{
return this;
}
foreach (var initializer in initializers)
{
_serviceCollectionInitializers.Add(initializer);
}
return this;
}
public ServiceCollectionInitializerRegistry WithAssemblyInitializers()
{
var assembly = Assembly.GetEntryAssembly();
var initializerTypes =
assembly.GetTypes()
.Where(type => typeof(IServiceCollectionInitializer).IsAssignableFrom(type));
if (!initializerTypes.Any())
{
return this;
}
foreach (var type in initializerTypes)
{
_serviceCollectionInitializers.Add((IServiceCollectionInitializer)Activator.CreateInstance(type));
}
return this;
}
public void Build()
{
var configuration = _serviceProvider.GetRequiredService<IConfiguration>();
foreach (var serviceCollectionInitializer in _serviceCollectionInitializers)
{
var logger = _serviceProvider.GetRequiredService<ILoggerProvider>()
.CreateLogger(serviceCollectionInitializer.GetType().AssemblyQualifiedName);
serviceCollectionInitializer
.Initialize(
configuration,
_serviceCollection, logger);
}
}
}
public class ExceptionHandlingInitializer : IServiceCollectionInitializer, IApplicationBuilderInitializer
{
public void Initialize(IConfiguration configuration, IServiceCollection services, ILogger logger)
{
services.AddSingleton<IExceptionMapper, ExceptionMapper>();
services.AddSingleton<IExceptionHandler, ExceptionHandler>();
}
public void Initialize(IConfiguration configuration, IApplicationBuilder builder, ILoggerFactory loggerFactory)
{
builder.UseExceptionHandlerMiddleware();
}
}

AutoMapper IMappingEngine ConfigurationStore Initialize Not Happening

AutoMapper Version Used : 3.3.10
[TestClass]
public class AppControllerTests
{
private IMappingEngine _mappingEngine = null;
private ConfigurationStore _configurationStore = null;
[TestInitialize]
public void SetUp()
{
_configurationStore = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
_configurationStore.AddProfile(new AutoMapperProfile.AppProfile());
_mappingEngine = new MappingEngine(_configurationStore);
}
[TestMethod]
public void GetAppByAccountID()
{
// Error line
var mappingResult = _mappingEngine.Map<Category>(categoryList).AsQueryable();
}
}
public class AppProfile : Profile
{
protected override void Configure()
{
AutoMapperMappingConfigurations();
}
public void AutoMapperMappingConfigurations()
{
Mapper.CreateMap<DomainModels.Category, Category>().ReverseMap();
}
}
Exception:
An exception of type 'AutoMapper.AutoMapperMappingException'
occurred in AutoMapper.dll but was not handled in user code.
Suspect the
_configurationStore.AddProfile(new OOS.PresentationModelService.AutoMapperProfile.AppProfile());
is not able to create an istance of AppProfile if i write the manual mapping it's working as expected.
_configurationStore.CreateMap<Category, Category>().ReverseMap();

Ninject issue with contextual binding and Lazy<T>

Ninject doesn't seem to correctly use WhenInjectedInto contstraint while also using Lazy<T>. Check the following example. The OnLandAttack and the OnLandAttackLazy should each be using the Samurai instance. But the Lazy<T> version ends up with the SpecialNinja instance. I'm guessing it's because it's not actually initialized in the contructor? But the type should still be correctly registered I would think. Am I missing something? FYI, this is using Ninject 3.2.2 and the Ninject.Extensions.Factory extension 3.2.1
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Load(new WarriorModule());
var amphibious = kernel.Get<IAttack>("amphibious");
amphibious.Execute();
var onLand = kernel.Get<IAttack>("onLand");
onLand.Execute();
var onLandLazy = kernel.Get<IAttack>("onLandLazy");
onLandLazy.Execute();
Console.ReadKey();
}
}
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWarrior>().To<Samurai>().WhenInjectedInto<OnLandAttack>();
Bind<IWarrior>().To<Samurai>().WhenInjectedInto<OnLandAttackLazy>();
Bind<IWarrior>().To<SpecialNinja>(); // <-- for everything else
Bind<IAttack>().To<AmphibiousAttack>().Named("amphibious");
Bind<IAttack>().To<OnLandAttack>().Named("onLand");
Bind<IAttack>().To<OnLandAttackLazy>().Named("onLandLazy");
}
}
public interface IWarrior
{
void Attack();
}
public class Samurai : IWarrior
{
public void Attack()
{
Console.WriteLine("\tSamurai Attack");
}
}
public class SpecialNinja : IWarrior
{
public void Attack()
{
Console.WriteLine("\tSpecial Ninja Attack");
}
}
public interface IAttack
{
void Execute();
}
public class OnLandAttack : IAttack
{
private readonly IWarrior warrior;
public OnLandAttack(IWarrior warrior)
{
this.warrior = warrior;
}
public void Execute()
{
Console.WriteLine("Begin OnLand attack");
this.warrior.Attack();
}
}
public class OnLandAttackLazy : IAttack
{
private readonly Lazy<IWarrior> warrior;
public OnLandAttackLazy(Lazy<IWarrior> warrior)
{
this.warrior = warrior;
}
public void Execute()
{
Console.WriteLine("Begin OnLandLazy attack");
this.warrior.Value.Attack();
}
}
public class AmphibiousAttack : IAttack
{
private readonly IWarrior warrior;
public AmphibiousAttack(IWarrior warrior)
{
this.warrior = warrior;
}
public void Execute()
{
Console.WriteLine("Begin Amphibious attack");
this.warrior.Attack();
}
}

NHibernate - Distributed transactions and providing your own connection result in exception

NHibernate is throwning an exception when particpating in a distirbuted transaction and you've opened a session by specifying your own connection object.
Unhandled Exception: System.InvalidOperationException: Disconnect cannot be call
ed while a transaction is in progress.
at NHibernate.AdoNet.ConnectionManager.Disconnect()
at NHibernate.Impl.SessionImpl.Close()
at NHibernate.Impl.SessionImpl.Dispose(Boolean isDisposing)
at NHibernate.Transaction.AdoNetWithDistrubtedTransactionFactory.<>c__Display
Class1.<EnlistInDistributedTransactionIfNeeded>b__0(Object sender, TransactionEv
entArgs e)
at System.Transactions.TransactionCompletedEventHandler.Invoke(Object sender,
TransactionEventArgs e)
at System.Transactions.TransactionStatePromotedCommitted.EnterState(InternalT
ransaction tx)
at System.Transactions.InternalTransaction.DistributedTransactionOutcome(Inte
rnalTransaction tx, TransactionStatus status)
at System.Transactions.Oletx.RealOletxTransaction.FireOutcome(TransactionStat
us statusArg)
at System.Transactions.Oletx.OutcomeEnlistment.InvokeOutcomeFunction(Transact
ionStatus status)
at System.Transactions.Oletx.OletxTransactionManager.ShimNotificationCallback
(Object state, Boolean timeout)
at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback
(Object state, Boolean timedOut)
The following code will reproduce the issue; reference the current FluentNibernate, and NHibernate 2.1.2.4000.
using System;
using System.Data.SqlClient;
using System.Transactions;
using FluentNHibernate.Mapping;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Cfg;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var cfg =
Fluently.Configure().Database(
MsSqlConfiguration.MsSql2008.ConnectionString("Integrated Security=SSPI;Data Source=.;Initial Catalog=Test").DefaultSchema("dbo")
).Mappings(x => x.FluentMappings.AddFromAssemblyOf<MyTableMap>()).BuildConfiguration();
using (var sf = cfg.BuildSessionFactory())
{
using (var ts = new TransactionScope().PromoteToDtc())
{
using (var conn = new SqlConnection("Integrated Security=SSPI;Data Source=.;Initial Catalog=Test"))
{
conn.Open();
using (var session = sf.OpenSession(conn))
{
session.Save(new MyTable { String = "Hello!" });
}
}
ts.Complete();
}
Console.WriteLine("It saved!");
Console.ReadLine();
}
}
}
public class DummyEnlistmentNotification : IEnlistmentNotification
{
public static readonly Guid Id = new Guid("E2D35055-4187-4ff5-82A1-F1F161A008D0");
public void Prepare(PreparingEnlistment preparingEnlistment)
{
preparingEnlistment.Prepared();
}
public void Commit(Enlistment enlistment)
{
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
enlistment.Done();
}
}
public static class TSExetensions
{
public static TransactionScope PromoteToDtc(this TransactionScope scope)
{
Transaction.Current.EnlistDurable(DummyEnlistmentNotification.Id, new DummyEnlistmentNotification(), EnlistmentOptions.None);
return scope;
}
}
public class MyTable
{
public virtual int Id { get; private set; }
public virtual string String { get; set; }
}
public sealed class MyTableMap : ClassMap<MyTable>
{
public MyTableMap()
{
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.String).Not.Nullable();
}
}
}
The issue is indeed with NHiberate. They're working on a patch. For reference, the issue can be found here