我有一个MVC Api端点,我正在创建一个包装api端点服务的api rest客户端项目。
我正在使用Entity框架,代码优先。
我的网络API项目如下:
project-mvc
project-core (this contains entity framework, models, etc.)
现在,当我创建我的rest api客户端项目时:
project-api-client
问题是,我必须引用项目核心,因为它包含模型,但后来我也得到实体框架,因为它是一个依赖。
所以我尝试创建一个单独的模型项目:
project-models
但它似乎仍然需要引用EntityFramework,否则我的属性似乎不起作用,例如:
public class Something
{
[Key]
[Column("Something_ID")]
public int Id { get; set; }
....
}
我认为您所需要的只是使用System.ComponentModel.DataAnnotations但我被迫引入了EntityFramwork。
我这样做错了吗?
答案 0 :(得分:3)
听起来你需要分离你的图层;一般来说,传递EF对象并更具体地将它们从控制器中传递到线上是一个坏主意,因为你最终可能会暴露出数据模型中客户没有兴趣(或业务)知道的部分。
一种解决这个问题的方法如下(注意:这个例子是在飞行中完成的,并不严格地说是“最好的”或者解耦最正确的方法,但是我想要反击你正确的方向)
<强>接口强> 您需要做的是定义一个界面,该界面描述客户端可能希望看到的MyThing的重要属性。您将此接口定义放在一个单独的项目中(假设为“MyInterfaces”)并从您的EF项目中引用此项目:
public interface IThing
{
int ID{get;set;}
string Data{get;set;}
}
数据传输对象 当你在它的时候,在Interfaces项目中创建一个具体的IThing数据传输对象:
public class MyThingDTO:IThing
{
public int ID{get;set;}
public string Data{get;set;}
}
注意:严格来说,这个模型应该在项目的各个“层”中重新实现,而接口项目应该只包含接口,但为了简单起见,我在所有层中使用相同的DTO。
<强>实体强> 现在,您可以在EF项目中定义类似这样的实体
public class MyThing:IThing
{
[Key]
[Column("MyThing_ID")
public int ID{get;set;}
[Column("MyThing_Data")
public string Data {Get;set;}
}
数据访问层 现在,您可以创建一个引用您的Entity Framework和Interface项目的数据访问层项目,并创建某种类,其作业是为IThings的请求提供服务
public class MyThingDataService
{
public IThing GetByID(int ID)
{
//EF code to query your database goes here, assuming you have a valid DBContext called "ctx". I won't go into how you might create or inject this, etc, as it's a separate topic e.g Dependency Injection.
var thing = ctx.MyThings.FirstOrDefault();
if (thing!=null)
{
return new MyThingDTO{ID=thing.ID, Data=thing.Data};
}
else{//handle the not found case here}
}
}
<强>参考强> 最后,从MVC项目中引用数据访问层和接口项目,现在控制器代码看起来像
public MyThing Get(int id)
{
//assuming you have an instance of MyThingDataService here, injected via DI or manually created, etc.
//strictly speaking we should declare our controller return type as IMyThing
//but this means we have to also decorate the DTO class with some attributes for the serialiser
//(KnownType) and I don't want to confuse things, hence the cast.
return dataService.GetByID(id) as MyThing;
}
现在,对EF项目的唯一引用是在中央接口项目中。
您的客户端项目只需要引用Interfaces项目(事实上您实际上并不需要这样做,因为您的客户端通过HTTP接收序列化数据,因此可以自由地实现自己对IMyThing接口的接受,但它很方便重新使用它只是为了节省时间。)
结束
我提到这只是朝着正确的方向发展 - 要建立一个真正分离的实现,你需要做更多的工作。 - 您的数据访问层也应该由接口定义,您应该使用某种DI容器将其注入MVC控制器; - 您的Interfaces项目应该只包含接口,每个层应该实现自己的具体类来表示流经它的数据(即它们都应该有自己的MyThingDTO风格实现IMyThing) - 当你这样做时,你会看到你有一个很好的解耦系统,因为没有任何层(MVC,数据访问,EF)彼此之间有任何引用,只有集中的Interfaces项目。 - 可能比我更聪明的人会发现你需要做的其他事情,因为我可能已经忘记了某些事情 - 这里很早(很晚?)。
反正。希望这会有所帮助。