9

In primo luogo, questo è legato ad un'altra domanda qui su SO:Entity Framework 6: Impossibile caricare la risorsa metadati specificato

ho letto e il debug il mio problema con il seguente articolo SO & blog:

MetadataException: Unable to load the specified metadata resource

e

http://blogs.teamb.com/craigstuntz/2010/08/13/38628/

MA ... Ho ancora domande al di là proprio questa 'correzione'

Ho un WebAPI (2.1), la stringa di connessione nel mio WebAPI è così:

<connectionStrings> 
<add name="ProjectEntities" connectionString=" 
    metadata=res://*/ProjectModel.csdl| 
    res://*/ProjectModel.ssdl| 
    res://*/ProjectModel.msl;   
    provider=System.Data.SqlClient;   
    provider connection string=&quot;   
    data source=192.168.0.1;   
    initial catalog=Project;   
    persist security info=True;   
    user id=***;   
    password=***;   
    multipleactiveresultsets=True;   
    App=EntityFramework&quot;" 
    providerName="System.Data.EntityClient" /> 

Quando chiamo ToList() su un DbSet nel mio WebAPI (pseudo codice):

DbContext _DbContext = new ProjectEntities(); 
DbSet<TEntity> _dbSet = _DbContext.Set<TEntity>(); 
_dbSet.ToList(); 

Funziona benissimo!

Quando chiamo la stessa all'interno di un WINDOWS SERVICE, ottengo il seguente errore: Error

La voce app.config per la stringa di connessione è esattamente la stessa della web.config:

<connectionStrings> 
<add name="ProjectEntities" connectionString=" 
    metadata=res://*/ProjectModel.csdl| 
    res://*/ProjectModel.ssdl| 
    res://*/ProjectModel.msl;   
    provider=System.Data.SqlClient;   
    provider connection string=&quot;   
    data source=192.168.0.1;   
    initial catalog=Project;   
    persist security info=True;   
    user id=***;   
    password=***;   
    multipleactiveresultsets=True;   
    App=EntityFramework&quot;" 
    providerName="System.Data.EntityClient" /> 

Ora, il blog mostra per fare riferimento al dll manualmente come così:

<connectionStrings> 
    <add name="ProjectEntities" connectionString=" 
     metadata=res://Project.Data.dll/ProjectModel.csdl| 
     res://Project.Data.dll/ProjectModel.ssdl| 
     res://Project.Data.dll/ProjectModel.msl;   
     provider=System.Data.SqlClient;   
     provider connection string=&quot;   
     data source=192.168.0.1;   
     initial catalog=Project;   
     persist security info=True;   
     user id=***;   
     password=***;   
     multipleactiveresultsets=True;   
     App=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" /> 
    </connectionStrings> 

questo non funziona/risolvere il problema

L'unico modo sono stato in grado di risolvere il problema, è quello di utilizzare il nome completo:

<connectionStrings> 
    <add name="ProjectEntities" connectionString=" 
     metadata=res://Project.Data, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null/ProjectModel.csdl| 
     res://Project.Data, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null/ProjectModel.ssdl| 
     res://Project.Data, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null/ProjectModel.msl;   
     provider=System.Data.SqlClient;   
     provider connection string=&quot;   
     data source=192.168.250.125\sqlexpress;   
     initial catalog=Project;   
     persist security info=True;   
     user id=***;   
     password=***;   
     multipleactiveresultsets=True;   
     App=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" /> 
    </connectionStrings> 

Perché funziona così? Perché dovrebbe funzionare in un progetto Web, ma non in un progetto di servizio Windows ?? Di recente ho cambiato da EF5 a EF6, e questo errore è apparso - tutto questo codice ha funzionato prima di aggiornare EF. Qualcuno ha qualche idea sul perché e come/se posso semplicemente usare * per il nome dll nella mia stringa di connessione?

ho pensato che fosse una questione di dove il servizio exe ​​ era in esecuzione e un file non è stato copiato a livello locale, ma no, il Project.Data.dll c'è ed è la versione giusta.

Ho usato FusionLog per cercare di trovare l'errore, e senza fortuna lì. Sono abbastanza confuso.

+0

Il servizio Windows è in esecuzione con credenziali diverse? Hanno i diritti appropriati per connettersi al server sql? – cadsjo

+0

Prova a cuocere la stringa di connessione nel codice per vedere se si tratta di un problema con il file rispetto alla connessione stessa. – Shoe

risposta

5

Perché questo succede?

Il problema si stanno avendo è solo il risultato di misure di sicurezza supplementari per prevenire piantare binario o DLL hi-jacking attacco (read more) quando si esegue l'applicazione come servizio di Windows.

Perché dovrei preoccuparmi?

Come probabilmente sapete, esiste uno specifico ordine well documented in cui viene cercato ogni file DLL di riferimento. Di solito inizia a cercare la DLL nella directory dell'applicazione corrente e poi si sposta in altre posizioni "pubbliche" come le cartelle PATH, GAC, ecc.

L'idea principale di un impianto binario è di installare un file DLL malevolo in una cartella che viene controllata prima cartella della legittima DLL. Il caricamento di tale DLL dannosa consentirebbe a un utente malintenzionato di ottenere il controllo del sistema.

In genere i servizi Windows vengono eseguiti con un account con privilegi elevati (LocalSystem, LocalService, NetworkService, ecc.) pertanto i servizi Windows sono un buon obiettivo per gli attacchi di binari.

Cosa posso fare?

Microsoft ha preso ulteriori precauzioni per ridurre i rischi per la sicurezza e c'è una buona ragione per questo. Ma puoi provare a risolvere i tuoi problemi.

1) directory corrente non è quello che ci si aspetta

servizio di Windows si avvia nella cartella di sistema (di solito qualcosa come C:\Windows\System32)

Una buona notizia è che è molto facile da risolvere. Devi solo cambiare la directory attuale all'avvio dei servizi.

System.IO.Directory.SetCurrentDirectory(System.AppDomain.CurrentDomain.BaseDirectory); 

Vedi blog post da Phil Haack;

2) Leggere la documentazione thoroughtly

Secondo EF documentation, carattere jolly ha un significato speciale e limita luoghi in cui runtime cercherà i file DLL:

If you specify a wildcard (*) for assemblyFullName, the Entity Framework runtime will search for resources in the following locations, in this order:

1) The calling assembly.

2) The referenced assemblies.

3) The assemblies in the bin directory of an application.

Come cartella di lavoro è impostato alla cartella di sistema e probabilmente i riferimenti non sono lì, EF potrebbe finire per cercare in posti sbagliati e gli assembly che contengono risorse potrebbero non essere caricati.

3) Massima sicurezza con i nomi di assemblaggio completamente qualificati

Anche se non sono del tutto sicuro di questo e non ho ancora testato, ma Microsoft ha appena potuto annullato servizi Windows per caricare DLL senza fornire il nome di montaggio completo ridurre il rischio di iniettare file DLL dannosi;

Buona lettura sulla protezione dei servizi Windows here (specialmente capitolo 5).

4) Eseguire il debug di questo!

EF6 sembra essere un progetto open source. Ciò significa che puoi ottenerne la piena fonte ed eseguirne il debug. È possibile trovare il progetto su CodePlex here.

+0

hmmm, sto testando questo presto, ma questo sembra rispondere alla domanda correttamente. Non so perché i punti premio siano stati assegnati a qualcun altro però !!!! –

+0

@SteveStokes Ho ricevuto i punti premio, perché la mia era la risposta votata più alta, dopo la fine del periodo di grazia della taglia. "Se non premi la tua taglia entro 7 giorni (più il periodo di grazia), la più alta risposta votata creata dopo che la taglia è iniziata con un punteggio minimo di 2 verrà assegnata metà della taglia." http://stackoverflow.com/help/bounty –

+0

Lo vedo ora, ma purtroppo non è la risposta migliore. –

2

Copia la DLL contenente ProjectEntities su un percorso diverso e quindi fa riferimento allo stesso nel progetto di servizio.

+0

Puoi spiegare un po 'meglio? Sono disposto a provare qualsiasi cosa –

-1

Si prega di seguire i passi sotto:

1.Write click sul file di edmx e quindi scegliere Apri con dell'entità correlata.

2. Selezionare editor xml e fare clic su Apri.

3. Scorrere dall'alto verso il basso del file .edmx xml e cercare eventuali segni di errore.

4.Se gli errori di mente li risolvono. 5.Rappresenta la soluzione e, se non si riscontrano errori, congratulazioni :)

1

Ho paura di non essere stato in grado di riprodurre l'errore ricevuto o di rispondere perché è stato necessario modificare lo metadata.

Detto questo, ho appreso che, per la stringa di connessione EF, il servizio di Windows richiedeva un diverso provider connection string rispetto a WebApi.

Di seguito sono riportati i passaggi per riprodurre l'errore. L'unica differenza è che sto usando localdb non SQLExpress.

Il codice risultante dai miei passaggi per la riproduzione è online su GitHub qui: https://github.com/bigfont/EntityFrameworkWindowsServiceWebApi.

Qui ci sono quei passi:

Creare Web API Progetto

  1. Creare ASP.NET Web API 2 progetto vuoto (MyWebApi)
  2. Con NuGet, Install-Package EntityFramework -ProjectName MyWebApi
  3. Aggiungi un nuovo ADO. Modello di dati di entità NET denominato MyProjectModel.
  4. Aggiungere un'entità denominata Entità1.
  5. Generare il database dal modello, chiamandolo MyProject e utilizzando localdb.
  6. eseguire lo script di creazione db su (LocalDB) \ v11.0
  7. Aggiungi un nuovo controller WebAPI nominato ValuesController con un metodo Get che interroga il database.
  8. test eseguendo in Visual Studio e andando a localhost: 123456/api/ottenere

See: https://msdn.microsoft.com/en-us/data/jj205424.aspx

Crea servizio Windows progetto

  1. creare il servizio di Windows (MyWindowsService)
  2. Utilizzare NuGet, Install-Package EntityFramework -ProjectName MyWindowsService
  3. Aggiungere un nuovo modello di dati di entità ADO.NET denominato MyProjectMode l.
  4. Aggiungere un'entità denominata Entità1.
  5. Generare il database dal modello, chiamandolo MyService, utilizzando localdb.
  6. Eseguire lo script di creazione del db su (localdb) \ v11.0
  7. Aggiungere al metodo OnStart del codice che interroga il database.
  8. Aggiungi NT AUTHORITY\SYSTEM come login localdb e come utente MyService db.
  9. di prova con l'installazione, a partire, e la scrittura di file:

installazione PowerShell, avvio e disinstallazione

Release> installutil .\MyWindowsService.exe 
Release> Start-Service MyService 
Release> installutil .\MyWindowsService.exe /u 

stringa di connessione LocalDB nel servizio di Windows

Nella stringa di connessione per il servizio di Windows, non ero in grado di utilizzare (localdb)\v11.0. Invece, avevo bisogno di usare la named pipe. Ho trovato la named pipe con questa riga di comando:

> SqlLocalDB.exe info v11.0 

Name:    v11.0 
Version:   11.0.2100.60 
Shared name: 
Owner:    MY_COMPUTER\Shaun.Luttin 
Auto-create:  Yes 
State:    Running 
Last start time: 2015-04-09 5:54:34 PM 
Instance pipe name: np:\\.\pipe\LOCALDB#1010101\tsql\query 

La stringa di connessione risultante, utilizzando il nome pipe istanza, sembrava come questo.

<connectionStrings> 
    <add name="MyProjectModelContainer" 
     connectionString=" 
    metadata= 
    res://*/MyProjectModel.csdl| 
    res://*/MyProjectModel.ssdl| 
    res://*/MyProjectModel.msl; 
    provider=System.Data.SqlClient; 
    provider connection string=&quot; 
    data source=np:\\.\pipe\LOCALDB#4BCE6D95\tsql\query; 
    initial catalog=MyService; 
    Integrated Security=True; 
    MultipleActiveResultSets=True; 
    App=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" /> 
    </connectionStrings> 

considerando che la stringa di connessione WebAPI si presentava così:

<add name="MyProjectModelContainer" 
     connectionString=" 
    metadata= 
    res://*/MyProjectModel.csdl| 
    res://*/MyProjectModel.ssdl| 
    res://*/MyProjectModel.msl; 
    provider=System.Data.SqlClient; 
    provider connection string=&quot; 
    data source=(localdb)\v11.0; 
    initial catalog=MyProject; 
    integrated security=True; 
    MultipleActiveResultSets=True; 
    App=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" /> 
    </connectionStrings> 

Vedi anche: http://www.connectionstrings.com/sql-server-2012/

bisogno di utilizzare una stringa di connessione diversa, con un servizio di Windows che facciamo con un progetto WebAPI è un problema simile a quello che hai trovato. Da Sql Server Management Studio, da Visual Studio e da WebApi, è possibile connettersi chiamando l'origine dati (localdb) \ v.11 mentre da un servizio Web è necessario chiamarlo tramite l'istanza denominata pipe.

Ecco un sospetto: è possibile che sul computer ci siano più istanze di localdb e che sia necessario specificare quale si desidera utilizzare. Sfortunatamente, questo non aiuta a rispondere perché è stato necessario modificare lo metadata.

Questo è un problema simile ma diverso da quello che si è dovuto affrontare, poiché era necessario modificare Entity Framework metadata mentre era necessario modificare lo provider connection string. Coincidenza?

+0

@downvoter Cura di commentare? –

+0

Certo - non è la soluzione corretta e non dovrebbe essere stata data la taglia. Ho downvoted per mettere la risposta corretta in cima - un servizio windows richiede la versione dll nella stringa di connessione per le meta risorse –

Problemi correlati