I have a WCF project with multiple layers ( and DTO object ) :
-Service ( WCF Host )
-Business Layer ( or Domain Layer )
-Data Access Layer ( using Entity framework )
To retrieve database informations , i want to use automapper to map Entity object To DTO object .
But if i configure mapping in global.asax , my problem is : the Service layer does not reference Data Access layer (and i dont want this).
How can i do ?
Thanks a lot.
Let's assume you're using AutoMapper 5.1, which includes profile scanning. First, you'd want to put your configuration into profiles at the appropriate places:
public class EntityToDtoProfile : Profile {
public EntityToDtoProfile() {
CreateMap<Entity, Dto>();
}
}
Next, in your WCF app, wherever the app startup is, you'll initialize AutoMapper, passing in the assembly names to scan for profiles:
Mapper.Initialize(cfg => {
cfg.AddProfiles(new [] {
"MyLayeredApp.BLL",
"MyLayeredApp.DAL",
"MyLayeredApp.Service"
});
});
AutoMapper will scan those assemblies for Profiles, and register them in the configuration. Make sure you only call Mapper.Initialize once at startup, like you would any other app-wide configuration.
Or, just create one WCF project, collapse all those projects into one, and use folders for organization instead of all this. That also works.
Related
I try to implement Microservice Architecture in my project. I was wondering can i create 1 method for Depedency Injection there is to implement EntityFrameworkCore in many services so i didnt DRY.
So what iam thinking is i still create my own DbContext, and than when i want to register this i just put it in my json file and add something like services.UseSql() in my startup.cs and inside UseSql is using Configuration from .json file.
what i try to say is something like generic DbContext.
I have some example to this but is using MongoDb :
Example
public static void AddMongo(this ContainerBuilder builder)
{
builder.Register(context =>
{
var configuration = context.Resolve<IConfiguration>();
var options = configuration.GetOptions<MongoDbOptions>("mongo");
return options;
}).SingleInstance();
builder.Register(context =>
{
var options = context.Resolve<MongoDbOptions>();
return new MongoClient(options.ConnectionString);
}).SingleInstance();
builder.Register(context =>
{
var options = context.Resolve<MongoDbOptions>();
var client = context.Resolve<MongoClient>();
return client.GetDatabase(options.Database);
}).InstancePerLifetimeScope();
builder.RegisterType<MongoDbInitializer>()
.As<IMongoDbInitializer>()
.InstancePerLifetimeScope();
builder.RegisterType<MongoDbSeeder>()
.As<IMongoDbSeeder>()
.InstancePerLifetimeScope();
}
If I understand your problem statement correctly, you want multiple microservices to connect to the same database. As comments above suggest, you really shouldn't do that as you'd essentially be coupling your microsrvices through your data layer - which can be messy if your microservices grow into incompatible data layers. This would eliminate a lot of benefits of the architecture and leave you to deal with pains. So if that is indeed the case you might want to consider revisiting your arсhitecture and trying to figure out whether you need a new microservice that fronts this common data store and provides it to others.
In reality however you sometimes must share code between projects and there's a official way to do that: extract the common code into a nuget package, host it somewhere in your private enterprise repository (if you care) and reference it from your other projects.
I've never worked with a .Net Core project before but have a history with .Net including MVC and entity framework. I'm working with a new .Net Core project which has five solution folders, EHA.PROJ.API, EHA.PROJ.DTO,EHA.PROJ.Repository, EHA.PROJ.Repository.Test and EHA.PROJ.Web. The EHA.PROJ.DTO folder has a number of files such as CategoryDTO.cs which looks like this
namespace EHA.PROJ.DTO
{
public class CategoryDescDTO
{
public int CategoryRef { get; set; }
public string CategoryName { get; set; }
}
}
I'm looking to set up a mapping arrangement to get the data from the EHA.PROJ.DTO files to the model files in my models folder in my EHA.PROJ.Web folder. I've been browsing as I've never done anything like this before as I've previously worked with data from a DAL folder using entity framework and connection done through connection strings. I'm guessing that there must be some process to map the data in my dbContext to connect the files in both folders. I did find some information on AutoMapper but was unsure how to implement it.
This arrangement with .Net Core is new to me so if anyone can help with any examples or point me in the right direction I would be grateful.
Your first problem is having your entities in your web project. Right off the bat, you have tight-coupling between the web project and your data layer, which then pretty much negates the point of all your other layers: DTO, repository, etc. You want to move out your entities and context into a true data layer (i.e. a class library project separate from your web project).
Then, you want to decide how far your data layer should extend. If the API is to feed the Website, then you want to actually remove all dependencies on the data layer from the web project. Your DTO project would be shared between the API and Web projects and your API would send/receive your DTOs, mapping back and forth from your entities under the hood.
However, if you're going to do that, then the repository project should just go away entirely. Just have your API work directly with EF and your entities. Your abstraction is the API itself; there is no need for another. The only reason to have the repository layer is if both the API and Web will both directly utilize the repositories, which isn't a very good pattern actually. You'll inevitably end up with a bunch of duplicated logic specific to each project.
Simply, the repository pattern is superfluous when using an ORM like EF. The ORM is your data layer. You're simply using a DAL provided by a third-party, rather than one you created yourself. The repository pattern only makes sense when working directly with SQL using something like ADO.NET directly. Otherwise, get rid of it.
Having an API is enough of an abstraction, if your goal is simply to hide the data layer. The website knows nothing of the underlying data source, and an API is really just a service layer that returns JSON over HTTP rather than object instances directly, i.e. the API is essentially your "repository" layer.
The situation can be improved even further by moving to a microservices-based architecture. With that, you essentially have multiple small, self-contained APIs that work with just one part of your domain or piece of functionality. Each can utilize EF directly, or an entirely different ORM, or even an entirely different stack. You could have APIs build on Node.js or python, etc. The website simply makes requests to the various services to get the data it needs and doesn't know or care how those services actually work.
I have been using Automapper for quite some time in .NET Core projects due to ease of use and built-in dependency injection.
Install from PM:
Install-Package AutoMapper
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection
Register in the Startup.cs, ConfigureServices method:
services.AddAutoMapper(typeof(Startup));
Create a class to keep your mappings, e.g. MappingProfile.cs using Profile from automapper, you can define mappings.
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Operator, OperatorDto>().ReverseMap();
}
}
}
The above mapping tells automapper that Operator can be mapped to OperatorDto and OperatorDto can be mapped to Operator.
In your controller, you can inject an IMapper
private readonly IMapper _mapper;
public OperatorsController(IMapper mapper)
{
_mapper = mapper;
}
and map values like below:
var dto = _mapper.Map<OperatorDto>(op); // Map op object to dto
var op = _mapper.Map<Operator>(dto); // Map dto to op object
Automapper offers custom mappings, should you need it.
While it is very easy to perform mappings with Automapper, you need to learn the framework.
I believe it is worth the effort to learn it as it will save you a lot of time writing mapping code in the future.
This article is a good reference to start: https://buildplease.com/pages/repositories-dto/
My suggestion is to have a DTO assembler that maps your model to the DTO object. So, you start with your DTO class:
namespace EHA.PROJ.DTO
{
public class CategoryDescDTO
{
public int CategoryRef { get; set; }
public string CategoryName { get; set; }
}
}
Then build the assembler:
public class CategoryDescAssembler {
public CategoryDescDTO WriteDto(CategoryDesc categoryDesc) {
var categoryDescDto = new CategoryDescDTO();
categoryDescDto.CategoryRef = categoryDesc.CategoryRef;
categoryDescDto.CategoryName = categoryDesc.CategoryName;
return categoryDescDto;
}
}
Now you implement the service to do all the work required to get the DTO object:
public class CategoryDescService : ICategoryDescService {
private readonly IRepository<CategoryDesc> _categoryDescRepository;
private readonly CategoryDescAssembler _categoryDescAssembler;
public CategoryDescService(IRepository<CategoryDesc> categoryDescRepository, CategoryDescAssembler categoryDescAssembler) {
_categoryDescRepository= categoryDescRepository;
_categoryDescAssembler= categoryDescAssembler;
}
public CategoryDescDTO GetCategoryDesc(int categoryRef) {
var categDesc = _categoryDescRepository.Get(x => x.CategoryRef == categoryRef);
return _categoryDescAssembler.WriteDto(categDesc);
}
}
With the interface looking like this:
public interface ICategoryDescService
{
CategoryDescDTO GetCategoryDesc(int categoryRef);
}
You would then need to add the service to your Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<ICategoryDescService, CategoryDescService>();
}
Now you can call your service from you view controller.
I am writing some Web API application, where I have 4 basic layers - API, BusinessLogic(which I call BusinessServices), DAL (which using EF to speak with the database), and EntitiesData(where I have my entities).
API calls businessService, bs ask DAL, DAL using EF is asking database about my EntitiesData.
Ok, now what's the problem ;)
On the BusinessServices, I want to map entities to some DTO, which I can return to API.
I wanted to use AutoMapper, but on tutorials, there are really simple examples, which I understand.
The first question: Should I use 2 IoC containers? Or maybe move my IOC from API to the business services layer?
1st Container is on API level and it contains BusinessServices (like UsesrsService, MessageService, etc.)
The second container would be at BusinessServices level - I want to use it to store my AutoMapper maps.
And this is the second question - what should I do with AutoMapper.
I know, how to create the configuration, did sth like this:
private void Congifure()
{
if(!(configuration == null))
return;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDto>();
cfg.CreateMap<Message,MessageDto>();
});
}
but what should I do now? pack it to the IoC container?
From which place in the code I should call my class which is configuring mapper?
In businessServices I have only my business-logic classes and DTO's.
You can pack it into your Startup.cs ConfigureServices method:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDto>();
cfg.CreateMap<Message,MessageDto>();
});
var mapper = config.CreateMapper();
services.AddScoped<AutoMapper.IMapper>(c => mapper);
And than inject it into your classes:
public class MyService
{
public MyService(IMapper mapper)
{
...
}
}
I would use one mapper, and put it somewhere vertically to your layer like into "helpers" project. Your mapper has to map between different layers so it should sit "between" them. Just move the logic of creation of MapperConfiguration into separate project and call it from your Startup.cs.
The very first thing in the automapper docs speaks about initialization. This should be done where ever you are bootstrapping your IOC container.
You only need 1 IOC container, making 2 would kind of make them useless as you would have broken the dependency tree into 2 halves.
And you should consider using mapping profiles for your different layers.
I have an N-Layer application as shown below
MyApp.Model - contains edmx and data models
MyApp.DataAccess - Repositories with EF
MyApp.Domain - Domain/business models
MyApp.Services - services(class library)
MyApp.Api - ASP.NET Web API
I am using Unity as my IoC container and Automapper for OO mapping.
My DataAccess layer references Model layer which contains all my Data objects.
I do not want to refer my model project in my Api layer. So returning DomainObjects (business models) from service layer and mapping to DTOs in API layer(DTOs are in API layer).
I configured domainModel to DTO mapping in API layer as below
public static class MapperConfig
{
public static void Configure() {
Mapper.Initialize(
config => {
config.CreateMap<StateModel, StateDto>();
config.CreateMap<StateDto, StateModel>();
//can't do this as I do not have reference for State which is in MyApp.Model
//config.CreateMap<State, StateModel>();
//config.CreateMap<StateModel, State>();
});
}
}
Now my question is how/where to configure my auto mapper mappings to convert my Entity models to Domain models?
To do in my API layer I do not have reference to my model project. I believe I should do this in service layer but not sure how to do that. Please help how to configure this mapping.
Note: Before asking here I googled with all eyes
Where to place AutoMapper map registration in referenced dll says to use static constructor which I do not think a good option to add in all my models (I have 100 models) and another answer says to use PreApplicationStartMethod for which I have to add reference to System.web.dll to my services which is not correct.
https://groups.google.com/forum/#!topic/automapper-users/TNgj9VHGjwg also did not answer my question properly.
You need to create mapping profiles in each of your layer projects, then tell AutoMapper to use those profiles in the topmost/outermost (invoking) layer that references all the lower layers. In your example:
MyApp.Model
public class ModelMappingProfile : AutoMapper.Profile
{
public ModelMappingProfile()
{
CreateMap<StateModel, StateDto>();
CreateMap<StateDto, StateModel>();
}
}
MyApp.Api
public class ApiMappingProfile : AutoMapper.Profile
{
public ApiMappingProfile()
{
CreateMap<State, StateModel>();
CreateMap<StateModel, State>();
}
}
MyApp.Services
Mapper.Initialize(cfg =>
{
cfg.AddProfile<MyApp.Model.ModelMappingProfile>();
cfg.AddProfile<MyApp.Model.ApiMappingProfile>();
});
or if you are using a DI container (e.g. SimpleInjector):
container.RegisterSingleton<IMapper>(() => new Mapper(new MapperConfiguration(cfg =>
{
cfg.AddProfile<MyApp.Model.ModelMappingProfile>();
cfg.AddProfile<MyApp.Model.ApiMappingProfile>();
})));
I've got 2 WCF services. Service A contains the definition of the type MyEntity. Service B contains a service reference to Service A and therefore can use the type for MyEntity. So I have a method that looks like this:
protected void Update (ServiceA.MyEntity entity)
{
//Do stuff
}
Now I want to use this method in Service A, so I added a service reference for Service B and tried:
protected UpdateServiceB(MyEntity entity)
{
using(ServiceB.ServiceClient client = new ServiceB.ServiceClient())
{
client.Update(entity);
}
}
This didn't work and complained that the types were not the same, even though Service B is using the type defined in Service A. How can I solve this?
UPDATE
I avoided the issue due to time constraints and passed the Guid of MyEntity from Service A to Service B instead. I then used an existing method called 'GetMyEntity(Guid entityId)' in Service A to retrieve the entity in Service B:
protected void Update (Guid entityId)
{
MyEntity entity = new MyEntity();
using (ServiceAClient client = new ServiceAClient())
{
entity = client.GetMyEntity(entityId);
}
//Do stuff
}
Sounds like you are using service references by way of Visual Studio's Add Service Reference command. While adequate, it can arguably become troublesome in medium to large projects due to:
Service types are re-defined in the client rather than using a common library (as you have discovered).
When a service contract changes, this will generally cause the service to be updated but not so in the client because of point 1. Client proxies become stale overtime as the schema evolves. You have to refresh reference
My best suggestion is not to use Add Service Reference and roll your client proxies by hand.
Once performed you will have additional libraries:
A.Contracts.dll - here you define all the service interfaces and data models for service A
B.Contracts.dll - here you define all the service interfaces and data models for service B
Common.Contracts.dll - If A & B have common types, place them here. (canonical data models)
A.Service.dll - service A implementation
B.Serivce.dll - service B implementation
ClientProxies.dll - roll-your-own client proxies for all your services
You don't have to implement all of the above now. All that is required is the manual ClientProxies.dll and you can always iterate to the rest later as required.
More
Tell me more about WCF the Right Way in my other SO answer