9

Po pierwsze, jest to związane z innego pytanie tutaj na SO:Entity Framework 6: Nie można załadować określony metadanych zasobu

Czytałem i debugowania mój problem z następujących SO artykuł & blogu:

MetadataException: Unable to load the specified metadata resource

i

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

ALE ... Nadal mam pytania poza tylko ten 'fix'

Mam WebAPI (2.1), ciąg połączenia w moim WebAPI jest tak:

<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" /> 

Kiedy zadzwonić ToList() na DbSet moim WebAPI (pseudo kod):

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

Działa świetnie!

Kiedy zadzwonić tego samego od wewnątrz usługi Windows, pojawia się następujący błąd: Error

Wpis app.config dla ciąg połączenia jest dokładnie taka sama jak 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" /> 

teraz blog pokazuje odwołać dll ręcznie tak:

<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> 

To nie działa/rozwiązać problem

jedyny sposób byli w stanie go naprawić, jest użycie nazwy w pełni kwalifikowaną:

<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> 

Dlaczego to działa w ten sposób? Dlaczego to działa w projekcie sieciowym, ale nie w projekcie usługi Windows? Niedawno zmieniłem EF5 na EF6, a ten błąd pojawił się - cały ten kod działał poprzednio przy uaktualnianiu EF. Czy ktoś ma jakiekolwiek wgląd, dlaczego i jak/jeśli mogę po prostu użyć * dla nazwy dll w ciągu połączenia?

myślałem, że to problem z którym usługa .exe został uruchomiony, a plik nie został skopiowany lokalnie, ale nope The Project.Data.dll istnieje i jest to właściwa wersja.

Użyłem FusionLog, aby spróbować znaleźć błąd i nie ma szczęścia. Jestem całkiem zdezorientowany.

+0

Czy Twoja usługa systemu Windows działa pod różnymi poświadczeniami? Czy mają odpowiednie uprawnienia do łączenia się z serwerem sql? – cadsjo

+0

Spróbuj wypalić ciąg połączenia w kodzie, aby sprawdzić, czy problem dotyczy pliku, a nie samego połączenia. – Shoe

Odpowiedz

5

Dlaczego tak się dzieje?

Wystąpił problem wynika tylko z dodatkowych środków bezpieczeństwa, aby zapobiec binarnemu sadzonemu lub atakowi hi-jacking DLL (read more) podczas uruchamiania aplikacji jako usługi Windows.

Dlaczego powinno mnie to obchodzić?

Jak zapewne wiesz, istnieje szczególna kolejność, w której każdy odnośny plik DLL jest sprawdzany. Zwykle zaczyna przeszukiwać bibliotekę DLL w bieżącym katalogu aplikacji, a następnie przechodzi do bardziej "publicznych" lokalizacji, takich jak foldery PATH, GAC itp.

Głównym założeniem binarnego sadzenia jest umieszczenie złośliwego pliku DLL w folderze sprawdzanym przed folder legalnej biblioteki DLL. Ładowanie takiej złośliwej biblioteki DLL umożliwi atakującemu przejęcie kontroli nad systemem.

Zwykle usługi Windows działają pod podwyższonym kontem (LocalSystem, LocalService, NetworkService, itp.), dlatego usługi Windows są dobrym celem ataków binarnych.

Co mogę zrobić?

Firma Microsoft podjęła dodatkowe środki ostrożności, aby zmniejszyć zagrożenia bezpieczeństwa i istnieje ku temu dobry powód. Ale możesz próbować rozwiązywać problemy.

1) Aktualny katalog nie jest to, czego można oczekiwać

usługa Windows uruchamia się w folderze systemowym (zazwyczaj coś jak C:\Windows\System32)

Dobre wieści są takie, że to jest bardzo łatwe do naprawienia. Trzeba tylko zmienić bieżący katalog przy uruchamianiu usług.

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

Zobacz blog post od Phila Haacka;

2) zapoznać się z dokumentacją thoroughtly

Według EF documentation, charakter wieloznaczny ma szczególne znaczenie, a to ogranicza miejsca, w których czas pracy będzie szukać plików 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.

jako folder roboczy jest ustawiony do folderu systemowego, a odniesienia prawdopodobnie nie istnieją, EF może skończyć szukając w niewłaściwych miejscach, a twoje złożenia zawierające zasoby mogą nie zostać załadowane.

3) Bądź bezpieczny w pełni kwalifikowanych nazw montażowych

Choć nie jestem całkowicie pewna i nie testowane, ale Microsoft po prostu mogło niedozwolone usług systemu Windows, aby załadować biblioteki DLL bez podania pełnej nazwy zespołu w celu zmniejszenia ryzyka wstrzyknięcia szkodliwych plików DLL;

Dobra wiadomość na temat zabezpieczania usług Windows here (specjalnie rozdział 5).

4) Debuguj go!

EF6 to projekt open source. Oznacza to, że możesz uzyskać pełne źródło i debugować go. Możesz znaleźć projekt na CodePlex here.

+0

hmmm, testuję to wkrótce, ale wydaje się, aby odpowiedzieć poprawnie na pytanie. Nie wiem, dlaczego punkty za bounty zostały przyznane komuś innemu !! –

+0

@SteveStokes Otrzymałem punkty za bounty, ponieważ moja była najwyższą głosowaną odpowiedzią, po zakończeniu okresu premiowego nagrody. "Jeśli nie przyznasz nagrody w ciągu 7 dni (plus okres karencji), najwyższa głosowana odpowiedź utworzona po rozpoczęciu nagrody, z minimalnym wynikiem 2, otrzyma połowę kwoty nagród." http://stackoverflow.com/help/bounty –

+0

Widzę to teraz, ale niestety nie jest to najlepsza odpowiedź. –

2

Skopiuj plik dll zawierający ProjectEntities do innej ścieżki, a następnie odwołaj się do niego w projekcie usługi.

+0

Czy możesz wyjaśnić trochę lepiej? Jestem gotów wypróbować cokolwiek –

-1

proszę wykonaj czynności poniżej:

1.Write kliknij na edmx pliku, a następnie kliknij polecenie Otwórz za pomocą powiązanego podmiotu.

2. Wybierz edytora xml i kliknij Otwórz.

3. Przewiń od góry do dołu pliku .edmx xml i poszukaj znaków błędu.

4. Jeśli myślisz o błędach, napraw to. 5. Zapoznaj się z rozwiązaniem i jeśli nie znaleziono błędów, to gratulacje :)

1

Obawiam się, że nie udało mi się odtworzyć błędu, który otrzymałeś, ani odpowiedzieć, dlaczego musisz zmienić metadata.

Powiedziałem, że nauczyłem się, że w przypadku ciągu połączenia EF usługa Windows wymagała innego provider connection string niż WebApi.

Poniżej przedstawiono czynności, które należy wykonać, aby odtworzyć błąd. Jedyna różnica polega na tym, że używam localdb, a nie SQLExpress.

Wynikowy kod z moich kroków do odtworzenia jest dostępny online na stronie GitHub tutaj: https://github.com/bigfont/EntityFrameworkWindowsServiceWebApi.

Oto te kroki:

tworzenie Web API projekt

  1. Tworzenie ASP.NET Web API 2 Empty Project (MyWebApi)
  2. Z Nuget, Install-Package EntityFramework -ProjectName MyWebApi
  3. dodać nowy ADO. Model danych encji NET o nazwie MyProjectModel.
  4. Dodaj podmiot o nazwie Entity1.
  5. Wygeneruj bazę danych z modelu, nazywając ją MyProject i używając localdb.
  6. Uruchom skrypt na tworzenie db (localdb) \ V11.0
  7. Dodaj nowy WebAPI Controller nazwie ValuesController z Get metody, która wysyła zapytanie do bazy danych.
  8. testu uruchamiając w Visual Studio i przechodząc do localhost: 123456/api/dostać

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

Tworzenie usługi Windows Projekt

  1. Tworzenie usługi Windows (MyWindowsService)
  2. Użyj NuGet, Install-Package EntityFramework -ProjectName MyWindowsService
  3. Dodaj nowy model danych obiektu ADO.NET o nazwie MyProjectMode l.
  4. Dodaj podmiot o nazwie Entity1.
  5. Wygeneruj bazę danych z modelu, nazywając ją MyService, używając localdb.
  6. Uruchom skrypt tworzenia bazy na (localdb) \ v11.0
  7. Dodaj do metody OnStart kod, który przeszukuje bazę danych.
  8. Dodaj NT AUTHORITY\SYSTEM jako lokalny login i jako użytkownik bazy danych MyService.
  9. testowania przez instalowanie, uruchamianie i pisanie do pliku:

PowerShell instalacji, uruchamiania i Odinstaluj

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

połączenie localdb ciąg w Windows Service

w ciągu połączenia dla usługi Windows, nie byłem w stanie użyć (localdb)\v11.0. Zamiast tego potrzebowałem użyć nazwanego potoku. Znalazłem nazwany potok z tym wierszem poleceń:

> 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 

Wynikowy ciąg połączenia, używając nazwy potoku instancji, wyglądał następująco.

<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> 

co następuje ciąg połączenia WebAPI wyglądał następująco:

<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> 

Patrz także: http://www.connectionstrings.com/sql-server-2012/

konieczności użyć innego ciąg połączenia z usługą Windows, które robimy z projektem WebAPI jest podobny problem do tego, co znalazłeś. Z Sql Server Management Studio, Visual Studio i WebApi, możemy się połączyć, wywołując źródło danych (localdb) \ v.11, podczas gdy z usługi sieciowej musimy wywołać to przez instancję o nazwie pipe.

Oto podejrzenie: Możliwe, że na komputerze znajduje się wiele instancji localdb i że musimy absolutnie określić, z którego chcemy skorzystać. Niestety, nie pomaga to w odpowiedzi na pytanie, dlaczego musisz zmienić metadata.

Jest to podobny, ale inny problem niż to, z którym się spotkałeś, ponieważ musisz zmienić Entity Framework metadata, podczas gdy muszę zmienić provider connection string. Zbieg okoliczności?

+0

@downvoter Care, aby skomentować? –

+0

Oczywiście - nie jest to właściwe rozwiązanie i nie powinno być przyznawane za nagrodę. Zgadzam się, aby umieścić poprawną odpowiedź na górze - usługa Windows wymaga wersji dll w ciągu połączenia dla meta zasobów –