WPF and EntityFrameworkCore - Adding migration gives "No database provider has been configured for this DbContext" - wpf

Note I have read the large number of SO answers that appear to be similar, but I am already doing what they suggested, so I don't know if there is some difference with WPF (they all seem to relate to ASP.NET). Also, most answers relate to run-time errors, not ones when adding migrations.
I'm trying to set up a .NET Core 3 WPF project that uses EntityFrameWork Core, but am having problems adding a migration. I have set up my context as follows...
public class ApplicationDbContext : DbContext {
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) {
}
public ApplicationDbContext() {
}
public DbSet<Product> Products { get; set; }
}
The parameterless constructor is there, as without it I get an exception Unable to create an object of type 'ApplicationDbContext' when trying to add a migration.
My App.xaml.cs contains the following...
public partial class App {
public IServiceProvider ServiceProvider { get; private set; }
public IConfiguration Configuration { get; private set; }
protected override void OnStartup(StartupEventArgs e) {
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appSettings.json", optional: false, reloadOnChange: true);
Configuration = builder.Build();
ServiceCollection serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
ServiceProvider = serviceCollection.BuildServiceProvider();
MainWindow mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
}
private void ConfigureServices(IServiceCollection services) {
// Configuration
services.Configure<AppSettings>(Configuration.GetSection(nameof(AppSettings)));
// Database
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SqlConnection")));
// Windows
services.AddTransient(typeof(MainWindow));
}
}
I realise that some of this is irrelevant, but thought I'd show the whole class in case it reveals something I missed. The code is based on this blog post.
However, when I try to add a migration, I get an exception "No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext."
As far as I can see, I have configured the database provider. I put a breakpoint in the ConfigureServices method, and can see that services.AddDbContext is called with the correct connection string.
Anyone any ideas what I've missed?
UPDATE I tried connecting to an existing database, and it worked absolutely fine, so it looks like the database provider has been configured correctly. It's only when I try to add a migration that I get the exception.
UPDATE 2 It seems that the migration tool is using the parameterless constructor on the context, which is why it thinks the provider hasn't been configured. If I remove the lines that configure it from App.xaml.cs, and instead override the OnConfiguringmethod to call UseSqlServer then the migration works fine. However, apart from the fact that I've not seen anyone else doing this (which makes me wonder if it's really the right way to do it), I don't see how to get the connection string from the config file. I can't inject an IConfiguration parameter, as the whole issue is that migrations requires a parameterless constructor.

It's actually quite simple with .Net Core 3.1 and EF Core Version 5, Entity Framework will look at the entry point class for the static function CreateHostBuilder, in my case that would be the App class in app.xaml.cs.
Not entirely sure the convention required prior to .Net Core 3.1. From my experience it had something to do with having a Startup class with .Net Core 2.1 and ASP.Net.
https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli
My solution:
public partial class App : Application
{
/// <summary>
/// Necessary for EF core to be able to find and construct
/// the DB context.
/// </summary>
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
// Configure Application services
.ConfigureServices((context, services) =>
{
ConfigureServices(context, services);
});
}
/// <summary>
/// Not necessary but I prefer having a separate function for
/// configuring services.
/// </summary>
private static void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
...
}
/// <summary>
/// Hold the built Host for starting and stopping
/// </summary>
private readonly IHost AppHost;
/// <summary>
/// Constructor
/// </summary>
public App()
{
// Create Application host
AppHost = CreateHostBuilder(new string[] { }).Build();
}
/// <summary>
/// App Startup Event Handler
/// </summary>
private async void Application_Startup(object sender, StartupEventArgs e)
{
// Start the application host
await AppHost.StartAsync();
...
}
/// <summary>
/// App Exit Event Handler
/// </summary>
private async void Application_Exit(object sender, ExitEventArgs e)
{
// Kill the application host gracefully
await AppHost.StopAsync(TimeSpan.FromSeconds(5));
// Dispose of the host at the end of execution
AppHost.Dispose();
}
}

You need to implement IDesignTimeDbContextFactory. There is a lot of hidden plumbing in an ASP.NET Core app that deals with wiring up the apps service provider so it can be found by the dotnet ef tooling, but no such plumbing exists in WPF. In addition the ef tools know nothing about WPF events so your OnStartup method isn't going to even be called (an instance the class wont even get created) to create your DI setup so that the ef tools can find your DBContext.
Move the code that creates the ServiceProvider into the constructor, other than the bit that looks up the main window and displays it.
Implement IDesignTimeDbContextFactory<ApplicationDbContext>. In the implemented CreateDbContext method return ServiceProvider.GetRequiredService<ApplicationDbContext>()
The tooling will then create an instance of your class, which will setup DI, and call that method to get your (now configured) DB Context and it should work.
I'd also recommend moving to HostBuilder based config (that blog post was written before the final version of Core 3 was released). You will find an updated version of the same post here

Related

How can I initialize a Prism module without View and ViewModel for working with EventAggregator?

I am writing an application using Prism that contains three modules. First one has a view to configure a "Person", second one is a service that generates that "Person" and third one is the visualization of all people. These three modules communicate with EventAggregator system. But I have problems with the messages on the service one.
In this service module I only have the service implementation and the module definition.
This service is a people manager that receives a message from EventAggregator, creates a "Person" with a task and send a message to the third module with this "Person".
Service:
private List<Person> people = new();
public PeopleControllerService(IEventAggregator eventAggregator, ICommonParametersService commonParameters)
{
this._eventAggregator = eventAggregator;
eventAggregator.GetEvent<GeneratePersonEvent>().Subscribe(GeneratePerson);
this._commonParameters = commonParameters;
}
private void GeneratePerson()
{
Person newPerson = new(this._commonParameters.DefaultPersonTask);
this.People.Add(newPerson);
this._eventAggregator.GetEvent<AssignedPersonEvent>().Publish(newPerson);
}
Module definition:
private PeopleControllerService moduleController;
public void OnInitialized(IContainerProvider containerProvider)
{
IEventAggregator eventAggregator = containerProvider.Resolve<IEventAggregator>();
ICommonParametersService commonParametersService = containerProvider.Resolve<ICommonParametersService>();
this.moduleController = new(eventAggregator, commonParametersService);
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
}
The problem is that when I send the "GeneratePersonEvent" message it never reaches the PeopleControllerService and the "GeneratePerson" method is never executed.
I've tried using a view and a viewModel, programming the service in the viewModel and assigning the view to a dummy and hidden region in the app and I've verified that it works that way.
Modified module definition:
public void OnInitialized(IContainerProvider containerProvider)
{
IRegionManager regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RequestNavigate(RegionNames.DummyRegion, "PeopleController");
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<PeopleController>();
}
How can I use the EventAggregator without using a dummy view? Do I have to add something in the "RegisterTypes" method? I've tried with:
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<PeopleControllerService>();
}
but it doesn't work either.
I've checked this post: Can I get EventAggregator Subscribe Message without view, viewmodel in prism?, and there it says that it is possible, but doesn't describe how to implement.
Most of the time you want exactly one instance of a service, and you have to tell the container:
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<PeopleControllerService>();
}
Also, you want your service to implement an interface so that you can pass different implementations to the consumers of your service, the most obvious case is your tests.
You need to actually create the instance of your service, too. Normally, you inject it into some consumer, but if it's completely decoupled and only talks through the event aggregator, you have to create the instance manually:
// in App.xaml.cs
protected override void OnInitialized()
{
Container.Resolve<PeopleControllerService>();
base.OnInitialized();
}
Hint: if the service implements an interface, the application doesn't need to personally know the controller module.

MVVM Light for Xamarin Forms and WPF

I'm trying to make an cross-plattform app, that will work for Xamarin.Forms and WPF (like this: https://github.com/C0D3Name/XamFormsWpf) in combination with MVVM light.
MVVM Light is quite new to me and i didn't find a clear tutorial for what i want to do. On Xamarin.Forms the DependencyInjection is done by
SQLiteConnection database = DependencyService.Get<ISQLite>().GetConnection("db.sqlite");
How is this done in MVVM light? Do i have to pass the different plattform-implementations of ISQLite in as parameter?
I already created the ViewModelLocator in my PCL:
public class ViewModelLocator
{
/// <summary>
/// Register all the used ViewModels, Services et. al. witht the IoC Container
/// </summary>
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
// My DataService is using the connection from ISQlite
SimpleIoc.Default.Register<IDataService, DataService>();
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
}
public interface ISQLite
{
SQLiteConnection GetConnection(string sqliteFilename);
}
As far as i understood the SimpleIoc, i have to register the interface to a concrete implementation, but how does my DataService know about the correct ISQLite Implementation?
I hope my question is understandable.
From official docs:
SimpleIoc - A very simple IOC container with basic functionality needed to register and resolve instances.
DependencyService - Xamarin.Forms allows developers to define behavior in platform-specific projects. DependencyService then finds the right platform implementation, allowing shared code to access the native functionality.
So you would want to use SimpleIoc to create your PCL dependency injection graph (IDataService for example)
And you will have to use DependencyService to provide platform specific functionality. One example for DependencyService use would be loading a html file located on the device into webview. Since the locations of assets on iOS and Android are different you will have add platform specific implementation for base url and then use DependencyService in your pcl. Another example would be IO.
So in your case if you need platform specific implementations of ISQlite you will have to use DependencyService. If not you may want (or not) to use SimpleIoc to add concrete implementation of ISQlite interface to your dependency graph.
Hope that helps.
Also have a look at Akavache. We use it with a great success in Xamarin.Forms projects.
Finally i found a working solution. The (async) Sqlite-Connection is used as parameter for my ViewModelLocator
public class App : Application
{
private static ViewModelLocator locator;
public static ViewModelLocator Locator
{
get
{
if (locator == null)
{
var connection = DependencyService.Get<ISQLite>().GetConnection("db.sqlite");
locator = new ViewModelLocator(connection);
}
return locator;
}
}
}
...and the locator injects the connection into the DataService constructor:
public class ViewModelLocator
{
public ViewModelLocator(SQLiteConnectionWithLock connection)
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<IDataService>(() => new DataService(connection));
// ViewModels
SimpleIoc.Default.Register<MainViewModel>();
}
public MainViewModel Main => ServiceLocator.Current.GetInstance<MainViewModel>();
}

How to initialize local fields of a WCF proxy class on deserialization

In my Silverlight client I have a partial class created by setting a WCF reference. I've extended this class adding a few RelayCommand properties. I need to initialize these properties which I would normally do in the constructor. However it seems that the constructor is not being called, which I believe is a result of of VTS However I'm also unsuccessful in using the OnDeserialized attribute.
What is the prescribed way to initialize client side data members of a WCF class.
I've created a sample project and everything works as expected. If this code doesn't help - post your data contract and client code.
namespace SilverlightApplication3.ServiceReference1
{
public partial class SomeModel
{
public string ExtendedProperty { get; set; }
[OnDeserializing]
public void OnDeserializingMethod(StreamingContext context)
{
this.ExtendedProperty = "Ok";
}
}
}
Service method call:
var proxy = new ServiceReference1.Service1Client();
proxy.DoWorkCompleted += (s,e) => Debug.WriteLine(e.Result.ExtendedProperty); //Ok
proxy.DoWorkAsync();

Integration Testing a ViewModel that calls WCF Services asynchronously in a WPF MVVM Application

The Silverlight Toolkit contains Unit Testing Functionality that allows to test classes such as the ViewModels in a MVVM application that invoke remote Services asynchronously.
I would like to be able to perform my ViewModel Integration Tests against the actual services instead of mocked instances.
Is there any support for asynchronous Unit/Integration Testing for WPF Applications?
Update:
At the end of the day my solution combined the suggestions of ktutnik and Alex Paven. I wrote a tiny helper class that adds some syntactic sugar:
public static class AsyncMethod
{
public delegate void AsyncMethodCallback(AsyncMethodContext ctx);
public static void Call(AsyncMethodCallback cb)
{
// create the sync object and make it available via TLS
using (var syncObject = new AutoResetEvent(false))
{
// call the decorated method
cb(new AsyncMethodContext(syncObject));
}
}
}
/// <summary>Asnc Method Callback Synchronization Context</summary>
public class AsyncMethodContext
{
public AsyncMethodContext(EventWaitHandle syncObject)
{
this.syncObject = syncObject;
}
private readonly EventWaitHandle syncObject;
/// <summary>
/// Waits for completion.
/// </summary>
public void WaitForCompletion()
{
syncObject.WaitOne();
}
/// <summary>
/// Signals the current operation as complete
/// </summary>
public void Complete()
{
syncObject.Set();
}
}
Here's a sample test case combined with the utilization of the Microsoft Rx Extensions:
[TestMethod]
public void TestGuestLogin()
{
AsyncMethod.Call((ctx) =>
{
var vm = ServiceLocator.Get<LoginDialogViewModel>();
// setup VM data
vm.Username = "guest";
vm.Password = "guest";
vm.AutoLogin = false;
GenericInfoEventArgs<LoginDialogViewModel.LoginRequestResult> loginResult = null;
// pre-flight check
Assert.IsTrue(vm.LoginCmd.CanExecute(null));
// create Observable for the VM's LoginRequestComplete event
var loginEvent = Observable.FromEvent<GenericInfoEventArgs<LoginDialogViewModel.LoginRequestResult>>(vm, "LoginRequestComplete").Do((e) =>
{
Debug.WriteLine(e.ToString());
});
// subscribe to it
var loginEventSubscription = loginEvent.Subscribe((e) =>
{
loginResult = e.EventArgs;
// test complete
ctx.Complete();
});
// set things in motion
using (loginEventSubscription)
{
vm.LoginCmd.Execute(null);
ctx.WaitForCompletion();
Assert.IsTrue(loginResult.Info.Success, "Login was not successful");
}
});
}
I was hunting for a long time for this feature but unlucky yet.
Not really a clean solution but it is work for me. I usualy used ManualResetEvent so the testing process not fall down until asynchronous done. Here is the idea:
//set false for initial state
resetEvent = new ManualResetEvent(false);
//do the test
myObjec.MakeMeHappyAssync();
//just wait until its state set
//when your call done
resetEvent.WaitOne();
//do assertion here
And somewhere in on your Complete Method or Fault Method you simply call
resetEvent.Set();
Anyway if you found any new information about the feature please let me know
Best Regard
You could look into Reactive Extensions, which are now included in .Net Framework 4, assuming you're using it; there are versions for 3.5 and Silverlight as well. They allow for some nice asynchronous coding, I've used them in unit testing before. See here for a blog article discussing it.

Issue intercepting property in Silverlight application

I am using Ninject as DI container in a Silverlight application. Now I am extending the application to support interception and started integrating DynamicProxy2 extension for Ninject. I am trying to intercept call to properties on a ViewModel and ending up getting following exception:
“Attempt to access the method failed: System.Reflection.Emit.DynamicMethod..ctor(System.String, System.Type, System.Type[], System.Reflection.Module, Boolean)”
This exception is thrown when invocation.Proceed() method is called. I tried two implementations of the interceptor and they both fail
public class NotifyPropertyChangedInterceptor: SimpleInterceptor
{
protected override void AfterInvoke(IInvocation invocation)
{
var model = (IAutoNotifyPropertyChanged)invocation.Request.Proxy;
model.OnPropertyChanged(invocation.Request.Method.Name.Substring("set_".Length));
}
}
public class NotifyPropertyChangedInterceptor: IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
var model = (IAutoNotifyPropertyChanged)invocation.Request.Proxy;
model.OnPropertyChanged(invocation.Request.Method.Name.Substring("set_".Length));
}
}
I want to call OnPropertyChanged method on the ViewModel when property value is set.
I am using Attribute based interception.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class NotifyPropertyChangedAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
if(request.Method.Name.StartsWith("set_"))
return request.Context.Kernel.Get<NotifyPropertyChangedInterceptor>();
return null;
}
}
I tested the implementation with a Console Application and it works alright.
I also noted in Console Application as long as I had Ninject.Extensions.Interception.DynamicProxy2.dll in same folder as Ninject.dll I did not have to explicitly load DynamicProxy2Module into the Kernel, where as I had to explicitly load it for Silverlight application as follows:
IKernel kernel = new StandardKernel(new DIModules(), new DynamicProxy2Module());
Could someone please help? Thanks
Reflection can be really tricky in silverlight because of security issues.
Check Gabe's answer for this question, it's the same problem.
The good news is that you can achieve the same functionality you want using dynamic instead of proxies. Just extend your ViewModel from DynamicObject and override the TrySetMember method.
I hope it helps :)

Resources