Reading config file from shell extension

134 Views Asked by At

I have a project that is set up as a shell extension with a SharpShell library. When I register it with regasm tool (with /codebase flag on) it works up until the point where I need to use the database via EntityNetwork. I get this error:

No connection string named 'EntitiesName' could be found in the application config file.

But of course I have the correct ConnectionString in the config file. It appears the whole config file is not being read at all.

So then I found a kind of a hack solution, I put this in the constructor:

    Dim assemblyLoc As String = [GetType].Assembly.Location
    Dim configName As String = assemblyLoc + ".config"
    AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configName)

and it appears something IS read, but not everything, I get a new error:

System.TypeInitializationException: The type initializer for 'System.Data.Entity.Internal.AppConfig' threw an exception. ---> System.Configuration.ConfigurationErrorsException: An error occurred creating the configuration section handler for entityFramework: Could not load file or assembly 'EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The system cannot find the file specified.

How can I use a config file or how can I use the EntityFramework with this kind of setup?

This is how my config file looks like:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <configSections>
        <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
      </configSections>
      <connectionStrings>
        <add name="EntitiesName" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string=&quot;***&quot;" providerName="System.Data.EntityClient" />
      </connectionStrings>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>
      <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
          <parameters>
            <parameter value="mssqllocaldb" />
          </parameters>
        </defaultConnectionFactory>
        <providers>
          <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
        </providers>
      </entityFramework>
    </configuration>

I suspect I might need to use Code-based configuration. If that's the case, I'd appreciate some vb.net pointers in that direction.

1

There are 1 best solutions below

0
On

After two days or so of frantically searching for some documentation (almost non existing for vb.net and even for c# always something missing) I put together these two classes:

Imports System.Data.Entity
Imports System.Data.Entity.Core.EntityClient
Imports System.Data.SqlClient

Partial Public Class MyConfig
    Inherits DbConfiguration

    Public Sub New()
        Me.SetProviderServices("System.Data.SqlClient", Entity.SqlServer.SqlProviderServices.Instance)
    End Sub
End Class

Public Class ConnectionStringBuilder
    Public Shared Function Construct() As String
        Dim newConnStringBuilder = New SqlConnectionStringBuilder With {
            .UserID = "user",
            .Password = "pass",
            .InitialCatalog = "database",
            .DataSource = "server"
        }
        Dim entityConnectionBuilder = New EntityConnectionStringBuilder With {
            .Provider = "System.Data.SqlClient",
            .ProviderConnectionString = newConnStringBuilder.ToString(),
            .Metadata = "res://*/Model1.csdl|
                            res://*/Model1.ssdl|
                            res://*/Model1.msl"
        }
        Return entityConnectionBuilder.ToString()
    End Function
End Class

Then, in edmx model class (in my case Model1.Context.vb) like so:

'------------------------------------------------------------------------------
' <auto-generated>
'     This code was generated from a template.
'
'     Manual changes to this file may cause unexpected behavior in your application.
'     Manual changes to this file will be overwritten if the code is regenerated.
' </auto-generated>
'------------------------------------------------------------------------------

Imports System
Imports System.Data.Entity
Imports System.Data.Entity.Infrastructure

<DbConfigurationType(GetType(MyConfig))>
Partial Public Class MyEntities
    Inherits DbContext

    Public Sub New()
        MyBase.New(ConnectionStringBuilder.Construct())
        'MyBase.New("name=MyEntities")
    End Sub

    Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
        Throw New UnintentionalCodeFirstException()
    End Sub

    Public Overridable Property XXXs() As DbSet(Of XXX)
    'etc...

End Class

I'm sure there could be a better approach, but so far this is the best I've got and I'm posting it here to potentially help and/or further discussion/correction.