Azure / azure-functions-vs-build-sdk

MSBuild task for Azure Functions
MIT License
99 stars 66 forks source link

Azure Functions cannot act as a startup project for EFCore #316

Open MisinformedDNA opened 6 years ago

MisinformedDNA commented 6 years ago

Steps to reproduce

I have three projects:

  1. A .NET Core library
  2. A .NET Core console app
  3. A .NET Core Azure Functions (v1) app

All three are using the EFCore.SqlServer 2.0 and EFCore.Tools 2.0 packages

If I try to add migrations to the library using the console app as the startup project, the migration is added as expected. However, if I try to the add the migrations using the Functions app, then I get an exception:

System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.EntityFrameworkCore.Design' or one of its dependencies. The system cannot find the file specified.
File name: 'Microsoft.EntityFrameworkCore.Design'
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Activator.CreateInstance(String assemblyString, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.AppDomain.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at Microsoft.EntityFrameworkCore.Tools.AppDomainOperationExecutor..ctor(String assembly, String startupAssembly, String projectDir, String contentRootPath, String dataDirectory, String rootNamespace, String environment)
   at Microsoft.EntityFrameworkCore.Tools.Commands.ProjectCommandBase.CreateExecutor()
   at Microsoft.EntityFrameworkCore.Tools.Commands.MigrationsAddCommand.Execute()
   at Microsoft.DotNet.Cli.CommandLine.CommandLineApplication.Execute(String[] args)
   at Microsoft.EntityFrameworkCore.Tools.Program.Main(String[] args)

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

Could not load file or assembly 'Microsoft.EntityFrameworkCore.Design' or one of its dependencies. The system cannot find the file specified.

Further technical details

TargetFramework: net461 EF Core version: 2.0 Database Provider: Microsoft.EntityFrameworkCore.SqlServer (2.0) Operating system: Win10 v1511 IDE: Visual Studio 2017 15.5.4 Other packages installed

EFCoreMigrations.zip

Per https://github.com/aspnet/EntityFrameworkCore/issues/10898, this is an issue with MSBuild parameters TargetDir and TargetPath.

bricelam commented 6 years ago

The data EF gets from MSBuild is incorrect:

Property Value
TargetDir C:\FunctionApp1\bin\Debug\net461\
TargetPath C:\FunctionApp1\bin\Debug\net461\FunctionApp1.dll

The actual assembly lives under bin\Debug\net461\bin\FunctionApp1.dll

christopheranderson commented 6 years ago

might be dupe - https://github.com/Azure/azure-functions-host/issues/2366

DibranMulder commented 6 years ago

It is actually possible, I wrote a Blogpost about it. You should add a netcoreapp target framework. For more information check the entire blogpost.

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFrameworks>netcoreapp2.0.7;netstandard2.0</TargetFrameworks>
    </PropertyGroup>

    ...

</Project>

https://dibranmulder.github.io/2018/08/23/Azure-functions-V2-with-EF-Core/

vitek-karas commented 5 years ago

@DibranMulder I just tried with the repro project I had and adding the two TFM didn't help. Still fails on the same error - the underlying problem being that Azure functions copies the output to a different folder than what the TargetDir/TargetPath points to.

mlapointe99 commented 5 years ago

I came up with a simple workaround. Since the EF commands are looking for the assembly in the TargetDir just copy it there with a post build command. copy /Y "$(TargetDir)bin\$(ProjectName).dll" "$(TargetDir)$(ProjectName).dll"

This doesn't fix the original post but it does for this issue https://github.com/dotnet/core-setup/issues/3965

Rocinante89 commented 5 years ago

I came up with a simple workaround. Since the EF commands are looking for the assembly in the TargetDir just copy it there with a post build command. copy /Y "$(TargetDir)bin$(ProjectName).dll" "$(TargetDir)$(ProjectName).dll"

This doesn't fix the original post but it does for this issue dotnet/core-setup#3965

Nice workaround. Is there a way I could automate that command so that it would work in a CI environment?

mlapointe99 commented 5 years ago

Rociante89 if your environment supports Powershell or command line steps that would be one way. Are you using AzureDevOps? That has a command line task that should be able to do this: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/command-line?view=azure-devops&tabs=yaml

Rocinante89 commented 5 years ago

Rociante89 if your environment supports Powershell or command line steps that would be one way. Are you using AzureDevOps? That has a command line task that should be able to do this: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/command-line?view=azure-devops&tabs=yaml

Ah awesome, I'm using DevOps so that should work nicely.

I'm getting this error right now so I'll have to sort that before I can move on to the Build/Release stage, but thanks for pointing me in the right direction!

Unable to create an object of type 'CheckinsContext'. For the different patterns supported at design time

ghost commented 5 years ago

@fabiocav - would you happen to know if there are any updates here? I'm trying to build my AzureFunction with entity frameworks and am running into the same issues as above.

I have tried both @mlapointe99 and @DibranMulder work arounds, but neither is getting me past this error:

doesn't reference Microsoft.EntityFrameworkCore.Design. This package is required for the Entity Framework Core Tools to work. Ensure your startup project is correct, install the package, and try again.

I originally landed on this page due to this issue https://github.com/aspnet/EntityFrameworkCore/issues/10898

bvmeer commented 5 years ago

I have a kind of workaround. I added a console application to my solution. The project has a reference to the project which contains the migrations

The code in this project, see below. To generate a migration i set this project as startup project and then create migration with the -p parameter which points to the database project.

``static class Program
{
    static void Main()
    {
        Console.WriteLine("This dummy app is only for generation of migrations.");
    }
}

public class MyDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
    public MyDbContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
        optionsBuilder.UseSqlServer(@"connectionstringdummy");

        return new MyDbContext(optionsBuilder.Options);
    }
}``
mahmoudsalahmis commented 4 years ago

https://github.com/aspnet/EntityFrameworkCore/issues/14679#issuecomment-550245010