Using EFProviderWrappers with precompiled views

One of the users has reported a problem with using EFProviderWrappers and precompiled views together.

When you pre-compile views, Entity Framework calculates a hash of metadata (which includes csdl,ssdl and msl information), stores it with the generated views and compares it later when metadata is loaded. When loaded metadata doesn’t match the hash stored in pre-compiled views, an exception is thrown.

Injecting a provider into provider chains involves changing SSDL file and that invalidates the hash.

Fortunately there’s a workaround, which enables you to use pre-compiled views and wrapper providers together, but you have to use the Alternative injection method as described in original blog post.

Let’s assume you have followed the steps outlined in the post and have your modified SSDL file ready. Injecting is a bit tricky because of additional registration required for EdmGen.exe to work. The first part involves creating a modified version of EdmGen.exe which can handle wrapper providers:

  1. Create a working directory (say “C:\ViewGeneration”)

  2. Copy %WINDIR%\Microsoft.NET\Framework\v3.5\EdmGen.exe and %WINDIR%\Microsoft.NET\Framework\v3.5\EdmGen.exe.config to that directory

  3. Open C:\ViewGeneration\EdmGen.exe.config using notepad

  4. Add Provider Registration section before the end of the configuration file so that it looks like this:

     <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <runtime>
        <generatePublisherEvidence enabled="false"/>
      </runtime>
      <!-- declare provider factories -->
      <system.data>
        <DbProviderFactories>
          <add name="EF Caching Data Provider"
               invariant="EFCachingProvider"
               description="Caching Provider Wrapper"
               type="EFCachingProvider.EFCachingProviderFactory, EFCachingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
          <add name="EF Tracing Data Provider"
               invariant="EFTracingProvider"
               description="Tracing Provider Wrapper"
               type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
          <add name="EF Generic Provider Wrapper"
               invariant="EFProviderWrapper"
               description="Generic Provider Wrapper"
               type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
        </DbProviderFactories>
      </system.data>
    </configuration>
    
  5. Copy EFTracingProvider.dll, EFCachingProvider.dll and EFProviderWrapperToolkit.dll to C:\ViewGeneration

(Alternatively you can just gac all the providers and put provider registration section in machine.config, but I think the described method is cleaner as it has only local impact and doesn’t require you to be an administrator).

Once you have the modified EdmGen.exe, you can use it for your view generation as usual, except that you pass modified ssdl file as an argument to /inssdl parameter.

 C:\ViewGeneration\EdmGen.exe 
    /mode:viewgeneration 
    /incsdl:NorthwindEFModel.csdl 
    /inssdl:NorthwindEFModel.WithTracing.ssdl 
    /inmsl:NorthwindEFModel.msl 
    /outviews:NorthwindEF.views.cs

This should create you NorthwindEF.views.cs which you can compile along with the rest of your application to get better startup performance.

Now, one more cool trick:

Wrapper-enabled EdmGen.exe can be used not just for view generation. For example it is possible to automatically generate a model from a database using EFTracingProvider! (this will create SSDL file which takes advantage of tracing automatically).

 C:\ViewGeneration\EdmGen.exe 
    /mode:FullGeneration
    /provider:EFTracingProvider
    /connectionString:"wrappedProvider=System.Data.SqlClient;server=.\SQLEXPRESS;database=NorthwindEF;integrated security=sspi" /project:NW

You can even use tracing provider during reverse-engineering process, to see what SQL statements are executed. All you need to do is add this section to C:\ViewGeneration\EdmGen.exe.config:

 <appSettings>
  <!-- this setting causes all log messages to be written to the console. -->
  <add key="EFTracingProvider.logToConsole" value="true" />
</appSettings>

Enjoy!