Entity Framework in een N-Tier en N-layered design
Momenteel ben ik met een project bezig dat met 2 tiers werkt (de database even niet meegerekend). Er is een presentatie laag (MVP) en deze staat in verbinding met een WCF service, de 2e tier. Deze 2e tier heeft dus een service laag, maar ook een business- (BL) en een data access laag (DAL). Dit is tegenwoordig een redelijk standaard design.
Omdat ik het Entity Framework wil gebruiken (https://jan-v.nl/post/entity-framework-4.0-in-een-n-tier-applicatie-met-wcf-implementeren/) zal alleen de DAL toegang moeten hebben tot het Model. De verschillende Entities worden wel in alle projecten gelinkt (service layer, busines layer en data access layer).
Het design heb ik al een tijd goed werkend, echter toen ik het geheel wilde gaan testen liep ik tegen problemen aan. De eerste fout die ik tegen kwam was de volgende:
ArgumentException: The specified named connection is either not found in the configuration, not intented tob e used with EntityClient provider, or not valid
Dit was al snel opgelost door de connectiestring in de web.config
van de service te plaatsen.
Nadat ik dat had gedaan kwam er een vervelende fout naar voren, namelijk:
MetadataException: Unable to load the specified metadata resource.
Er is hier veel over te vinden op het internet en komt er op neer dat de metadata van de edmx niet in de dll zijn meegenomen, of dat de referenties in de connectiestring niet correct zijn.
Een van de oplossingen is dan om in dit gedeelte van de connectiestring:
metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl
de * tekens te vervangen met de naam van de dll, dan zou er zoiets moeten komen te staan:
metadata=res://ModelProject/Model.csdl|res://ModelProject/Model.ssdl|res://ModelProject/Model.msl
De reden om dit te doen, is omdat de applicatie blijkbaar moeite kan hebben met het vinden van de benodigde bestanden binnen de dll’s.
Nog een oplossing zou kunnen zijn om de Metadata Artifact Processing te wijzigen.
Deze staat normaal op Embed in Output Assembly
, maar zou dan op Copy to Output Directory
gezet kunnen worden. De aangemaakte bestanden (csdl, ssdl en msl) moeten dan handmatig worden gekopieerd naar de root
of bin
map van de service, afhankelijk van wat je in de web.config
zet.
Beide opties boden mij geen oplossing. Tijdens het zoeken naar een oplossing voor m’n probleem merkte ik op dat de dll van het Model project niet in m’n bin map werd geplaatst. Dan is het natuurlijk logisch dat de metadata niet gevonden kan worden, aangezien die ook niet aanwezig is.
Na veel zoeken heb ik nergens een antwoord kunnen vinden dat mij zou helpen. Overal werd in de service ook gelijk een verbinding gemaakt naar het Model, waardoor alles goed gaat. Vandaag had ik ineens een helder moment. Het kan natuurlijk zijn dat .NET/Visual Studio vind dat het Model project niet nodig is. Als ik de code zo een beetje door kijk, dan wordt nergens iets van het Model project gebruikt. Er is alleen een Reference
gemaakt binnen het DAL project, maar dat is dan ook alles. Hierdoor zal de compiler waarschijnlijk denken dat het project overbodig is en dus niet in de bin map plaatsen.
Een kleine test bevestigde mijn vermoeden. Nadat ik een lege klasse had aangemaakt in het Model project en deze in de DAL gebruikte werd de Model dll ook in de bin map geplaatst.
In het Model project heb ik dus het volgende aangemaakt:
namespace OnsKoopje.Model
{
public class Empty
{
}
}
In m’n DAL project heb ik nu de volgende code geplaatst:
class ModelLink
{
private ModelLink()
{
var ep = new Model.Empty();
}
}
Aangezien het Model project nu wordt gebruikt in de DAL, wordt de dll nu ook mee gekopieerd naar de output directory van de service.
Het is een beetje een work-around voor het probleem, maar het werkt! Hopelijk wordt dit in de toekomst nog eens opgelost, tenzij ik echt met exotische dingen bezig ben, maar dat lijkt mij niet.