I'm following the repository pattern with service layers in my project.
For each view I'm going to create a viewmodel.
What I'm confused is that, should the service layer directly access domain objects and returns them to the controller, or should I use DTOs. If I should use DTOs, where to put them in the project architecture?
Thank you.
Service layer is responsible for mapping (converting) Dto objects and Domain objects by implementing proper business logic.
Your DTO objects should be used in controllers and services.
DTO's are transfered between Controller and Service, on the other hand Domain objects are transfered between Service and Repository
Controller does not know about Domain and Repository does not know about DTO. Service knows both DTO and Domain and converts them each other with business rules like a car between driver and road, like stackoverflow between you and me, like everything, abstraction...
Following code is an example. Consider each namespace is a package.
namespace Controllers
{
using Services;
using DataTransferObjects;
public class CoffeeController
{
public ICoffeeService CoffeeService { get; set; }
public JsonResult GetCoffee(GetCoffeeInDto inDto)
{
var result = CoffeeService.GetCoffee(inDto);
return JsonResult(result);
}
public JsonResult SaveCoffee(SaveCoffeeInDto inDto)
{
var outDto = CoffeeService.SaveCoffee(inDto);
return JsonResult(outDto);
}
}
}
namespace Services
{
using DataTransferObjects;
public interface ICoffeeService
{
GetCoffeeOutDto GetCoffee(GetCoffeeInDto inDto);
SaveCoffeeOutDto SaveCoffee(SaveCoffeeInDto inDto);
}
}
namespace Services.Impl
{
using Services;
using Repository;
using DataTransferObjects;
using Domain;
public class CoffeeService : ICoffeeService
{
public ICoffeeRepository CoffeeRepository { get; set; }
public GetCoffeeOutDto GetCoffee(GetCoffeeInDto inDto)
{
var entity = CoffeeRepository.Get(inDto.Id);
return new GetCoffeeOutDto {Id = entity.Id, Name = entity.Name};
}
public SaveCoffeeOutDto SaveCoffee(SaveCoffeeInDto inDto)
{
var entity = new CoffeeEntity {Name = inDto.Name};
CoffeeRepository.Save(entity);
return new SaveCoffeeOutDto {Id = entity.Id};
}
}
}
namespace Repository
{
using Domain;
public interface ICoffeeRepository
{
CoffeeEntity Get(int id);
void Save(CoffeeEntity coffeeEntity);
}
}
namespace Repository.Impl
{
using Repository;
using Domain;
public class CoffeeRepository:ICoffeeRepository
{
public CoffeeEntity Get(int id)
{
//get entity from db
throw new System.NotImplementedException();
}
public void Save(CoffeeEntity coffeeEntity)
{
//insert entity into db
throw new System.NotImplementedException();
}
}
}
namespace DataTransferObjects
{
public class SaveCoffeeInDto
{
public string Name { get; set; }
}
public class SaveCoffeeOutDto
{
public int Id { get; set; }
}
public class GetCoffeeInDto
{
public int Id { get; set; }
}
public class GetCoffeeOutDto
{
public int Id { get; set; }
public string Name { get; set; }
}
}
namespace Domain
{
public class CoffeeEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Related
I am trying to use MVC with a controller a view a model and the database.
But I premise I do not know how to use entity framework in my case to connect the model and the database. So I get this runtime error:
"InvalidOperationException: Unable to resolve service for type 'WebCoreFly.Models.FlightsList' while attempting to activate 'WebCoreFly.Controllers.HomeController"
My code consists in:
the controller code:
public class HomeController : Controller
{
private FlightsList l;
public HomeController(FlightsList theList)
{ l = theList; }
public ViewResult Index()
{
return View(l.Flights);
}
}
the Model Code for Flights:
public partial class Flights
{
public long ID { get; set; }
public long Id_Destination { get; set; }
public string Id_Source { get; set; }
public string Nome { get; set; }
public string Company { get; set; }
public System.DateTime Time { get; set; }
public string Id_Plane { get; set; }
public Nullable<System.DateTime> TimeOfArrival { get; set; }
}
and the model for FlightsList:
public class FlightsList
{
private FlyDBContext context;
public FlightsList(FlyDBContext ctx)
{
context = ctx;
}
public IQueryable<Flights> Flights => context.Flights;
}
finally I have defined my dbcontext:
public class FlyDBContext : DbContext
{
public FlyDBContext(DbContextOptions<FlyDBContext> options)
: base(options)
{
}
public DbSet<WebCoreFly.Models.Passengers> Passengers { get; set; }
public DbSet<WebCoreFly.Models.Bookings> Bookings { get; set; }
public DbSet<WebCoreFly.Models.Flights> Flights { get; set; }
}
And in my startup code, I configure services to accept my dbcontext with a link to Existing SQL Database called Fly:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<FlyDBContext>(options =>
options.UseSqlServer(#"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Fly;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"));
}
And this is the Configure method of startup:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
My question is: who is responsible to pass to my controller the flights list? and since the flightlist is tied to the dbcontext, is the problem somehow related to the fact I did not use entityframework? (For semplicity Idid not post the code for my view, but I can do it if necessary)
the issue is coming because of the dependency Injection. Here How the application would know that Flights List object requires in Home Controller. To fix this you have to configure it in StartUp.Cs class Configure Service method.
services.AddSingelton<FlightsList>();
There are various ways to configure it like Transient, AddScoped etc.
It is better if you use repository pattern here. Register here the Interface. like following.
services.AddSingelton<IRepository, FlightsList>();
In controller side.
public class HomeController : Controller
{
private IRepository l;
public HomeController(IRepository theList)
{ l = theList; }
public ViewResult Index()
{
return View(l.Flights);
}
}
Hope it will help.
I am working on a project that uses an MVC API with Entity Framework 6.1.3. We need to implement Get, GET/ID, Insert, Update and Delete API's.
for Insert and Update we have a parameter class that is not the same one as the DB, i am not sure what will be the best solution for that.
For an Update (the one that i have more questions) i can find a record and then update all properties manually, this is something i want to avoid. If i use the currentvalues from the entity then i will have to set the ExtraValues properties in all the apis that i am going to write, that kind of looks weird.
Note: i want to have a child class since most of the entities uses the same fields (Created/Updated) so instead of having those in all the classes i rather have them as inheritance.
There has to be a better solution for this problem, could someone help with ideas or best ways to do this.
public class DBClassA : ExtraValues
{
public int ID { get; set; }
public string Name { get; set; }
}
public class DBClassB : ExtraValues
{
public int ID { get; set; }
public string Name { get; set; }
}
//This will be use in all the classes
public class ExtraValues
{
public string SameValueInOtherClasses { get; set; }
public string SameValueInOtherClasses2 { get; set; }
public string SameValueInOtherClasses3 { get; set; }
}
[HttpGet]
public List<DBClassA> Get()
{
return new List<DBClassA>();
}
[HttpGet]
public DBClassA Get(int ID)
{
return new DBClassA();
}
[HttpPost]
public HttpResponseMessage Insert(DBClassA obj)
{
using (var context = new DBEntities())
{
context.Entity.Attach(DBClassA);
context.SaveChanges();
}
return Request.CreateResponse(HttpStatusCode.OK);
}
[HttpPut]
public HttpResponseMessage Update(int ID, DBClassA obj)
{
using (var context = new DBEntities())
{
var entity = context.Entity.Find(ID);
//I will have to put the ExtraValues here
obj.ExtraValues = "";
_context.Entry(entity).CurrentValues.SetValues(obj);
context.SaveChanges();
}
return Request.CreateResponse(HttpStatusCode.OK);
}
using (var db = new DBEntities())
{
db.Entry(obj).State = EntityState.Modified;
db.SaveChanges();
}
more info: http://www.entityframeworktutorial.net/EntityFramework4.3/update-entity-using-dbcontext.aspx
I am a newbie learning ASP.NET MVC from book.I am using NInject to Implement IoC. I have created a data model for Job and Location as below
Table Name - JobDetails
JobId<PK>
LocationId<FK>
JobName
Table Name - Location
LocationId<PK>
LocationName
I have created Entities for Location and JobDetails as Below
JobDetails
public class JobDetails
{
[Key]
public int JOBID { get; set; }
public int LocationID { get; set; }
public string JOBNAME { get; set; }
}
Location
public class Location
{
[Key]
public int LocationID{ get; set; }
public string LocationName { get; set; }
}
Also I have my Abstract and Context Class for Job Details and Location as below
public interface IJobDetails
{
IEnumerable<JobDetails> jobDetailsInterface { get; }
}
public interface ILocation
{
IEnumerable<Location> locationInterface { get; }
}
public class EFLocationRepository : ILocation
{
public EFDbContext context = new EFDbContext();
public IEnumerable<Location> locationInterface
{
get { return context.Location; }
}
}
public class EFJobRepository : IJobDetails
{
public EFDbContext context = new EFDbContext();
public IEnumerable<JobDetails> jobDetailsInterface
{
get { return context.JobDetails; }
}
}
My Model class for Job and Location are as below
public class JobListViewModel
{
public IEnumerable<JobDetails> jobDetails { get; set; }
}
public class LocationListViewModel
{
public IEnumerable<Location> Location { get; set; }
}
In my JobDetail Controller I want to display the location name instead of Location Id.
My JobDetail controller is as below
public class JobController : Controller
{
public IJobDetails repository;
public JobController(IJobDetails job)
{
repository = job;
}
public ViewResult List()
{
return View(repository.jobDetailsInterface);
}
}
How to display Location Name instead of Location id in my Job View?
N.B-I am learning MVC from Adam Freeman book and trying to create something new.Please let me know what I have done is correct or not.
Adding to sleeyuen's response. You may want to add a "navigation" property to JobDetails model, like below:
public class JobDetails
{
[Key]
public int JOBID { get; set; }
public int LocationID { get; set; }
public string JOBNAME { get; set; }
public virtual Location JobLocation { get; set; }
}
Then you should be able to access Location name from view by doing: repository.jobDetailsInterface.JobLocation.LocationName
In your scenario I believe entity framework will be able to infer relationships from the model structure, so you won't need entity configuration set up
Please note, this approach leads to N+1
Hope this helps :)
i am using Database first method. EDMX file generated default Dbset(TableName) for me.
myDbContext.Table1.ToList();
myDbContext.Table2.ToList();
Can we have a ModelView Class which pull both table out with single line?
Instead of
Table1=myDbContext.Table1.ToList();
Table2=myDbContext.Table2.ToList();
can we have like
ModelView=myDbContext.ModelView;
Updated
public partial class ProductTb
{
public string ProductID { get; set; }
public string ProductArticleNumber { get; set; }
public string ProductName { get; set; }
}
public partial class ProductTbTWO
{
public string ProductID { get; set; }
public string ProductArticleNumber { get; set; }
public string ProductName { get; set; }
}
public class ProductModelView
{
public ProductTb{get;set;}
public ProductTbTWO{get;set}
}
Create a Partial Class of your DbContext and add your custom Code.
public partial class MyDbContext
{
private MyDbContext(string contextName) : base(contextName) { }
public static MyDbContextCreate() {
return new MyDbContext(ContextName);
}
public ProductModelView ModelView {// Get ProductTb and ProductTbTWO}
}
and use it var myDbContext= MyDbContext.Create() and myDbContext.ModelView
But I don't recommend to do something like that, Add a Service class to with public method to get your code, Data Layer shouldn't deal with View Models
i prefer using static class:
public static class Utilities
{
public static ProductModelView getProductViewModel()
{
using (var db = new myDbContext()
{
var vm = new ProductModelView();
vm.ProductTb = db.ProductTb.ToList();
vm.ProductTbTWO = db.ProductTbTWO.ToList();
return vm;
}
}
}
you can call it like:
var vm = Utilities.getProductViewModel();
I got dbset for table Functions in database and FunctionsContext: dbContext. I am implementing repository. In my interface I have only one function at the movement "GetFunctions". I got stuck in implementing class; method "GetFunctions" where I need to call FunctionsContext to get all list of available functions title from database and then send to controller class
I am using mvc5 asp.net and entity framework
dbContext
public class FunctionsContext : dbContext
{
public DbSet<App_Functions> Functions { get; set; }
}
model
[Table("Functions")]
public class App_Functions
{
[Key]
public int Function_ID { get; set; }
[StringLength(50)]
[Required]
public string Title { get; set; }
public int Hierarchy_level { get; set; }
}
Domain Class
public class Functions
{
public Functions()
{
}
public int Function_ID { get; set; }
public string Title { get; set; }
public int Hierarchy_level { get; set; }
}
IRepository
interface IFunctionRepository: IDisposable
{
IQueryable<Functions> GetFunctions { get; }
}
IRepository Implementation class
public class FunctionRepository : IFunctionRepository
{
private FunctionsContext fun_Context = new FunctionsContext();
public IQueryable<Functions>GetFunctions
{
?????????
}
}
what I want to implement in IQueryableGetFunctions
using (var db = new FunctionsContext())
{
var query = from b in db.Functions
orderby b.Function_ID
select b;
foreach (var item in query)
{
var a2 = item.Title;
}
}
I think the easiest way will be the following:
public IQueryable<Functions> GetFunctions()
{
return fun_Context.Functions.Select(x=>new Functions {
Function_ID = x.Function_ID,
Title = x.Title,
Hierarchy_level = x.Hierarchy_level
});
}
You have to add () after the method name, this declaration does not work 'public IQueryable GetFunctions'
IRepository Implementation class
public class FunctionRepository : IFunctionRepository
{
private FunctionsContext fun_Context = new FunctionsContext();
// For method declaration add the () after the method name
public IQueryable<Functions> GetFunctions()
{
return fun_Context.Functions;
}
}