C# 我的Web Api Rest客户端迫使我引用实体框架

C# 我的Web Api Rest客户端迫使我引用实体框架,c#,asp.net-mvc,asp.net-web-api,C#,Asp.net Mvc,Asp.net Web Api,我有一个MVCAPI端点,我正在创建一个Api rest客户机项目,它也包装了Api端点服务 我使用的是实体框架,代码优先 我的web api项目看起来像: project-mvc project-core (this contains entity framework, models, etc.) 现在,当我创建rest api客户端项目时: project-api-client 问题是,我必须引用项目核心,因为它包含模型,但我也得到实体框架,因为它是依赖性的 因此,我尝试创建一个单独的

我有一个MVCAPI端点,我正在创建一个Api rest客户机项目,它也包装了Api端点服务

我使用的是实体框架,代码优先

我的web api项目看起来像:

project-mvc
project-core  (this contains entity framework, models, etc.)
现在,当我创建rest api客户端项目时:

project-api-client
问题是,我必须引用项目核心,因为它包含模型,但我也得到实体框架,因为它是依赖性的

因此,我尝试创建一个单独的模型项目:

project-models
public class MyThingDTO:IThing
{
   public int ID{get;set;}
   public string Data{get;set;}
}
但它似乎仍然必须引用EntityFramework,否则我的属性似乎不起作用,例如:

public class Something
{

        [Key]
        [Column("Something_ID")]
        public int Id { get; set; }

    ....
}
我以为您需要的只是使用System.ComponentModel.DataAnnotations,但我不得不引入EntityFramwork


我做错了吗?

听起来你需要解耦你的层;一般来说,传递EF对象,更具体地说,将它们从控制器中抛出是一个坏主意,因为最终可能会暴露客户不感兴趣(或不感兴趣)的部分数据模型

纠正这种情况的一种方法如下(注意:这个示例正在进行中,严格来说不是“最佳”或最解耦的正确方法,但我想让您朝着正确的方向前进)

接口 您需要做的是定义一个接口,该接口描述客户机可能希望看到的神话的重要属性。您将此接口定义放在单独的项目中(比如“MyInterfaces”),并从EF项目中引用此项目:

public interface IThing
{
   int ID{get;set;}
   string Data{get;set;}
}
数据传输对象 同时,在Interfaces项目中创建一个具体的实现数据传输对象:

project-models
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;}
}
数据访问层 现在,您可以创建一个数据访问层项目,该项目引用您的实体框架和接口项目,并创建某种类,该类的任务是为iThing请求提供服务

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)相互引用,只引用集中接口项目。 -也许比我聪明的人会发现你需要做的其他事情,因为我可能忘记了一些事情——现在很早(很晚?)


无论如何。希望这能有所帮助。

听起来你需要分离你的层;一般来说,传递EF对象,更具体地说,将它们从控制器中抛出是一个坏主意,因为最终可能会暴露客户不感兴趣(或不感兴趣)的部分数据模型

纠正这种情况的一种方法如下(注意:这个示例正在进行中,严格来说不是“最佳”或最解耦的正确方法,但我想让您朝着正确的方向前进)

接口 您需要做的是定义一个接口,该接口描述客户机可能希望看到的神话的重要属性。您将此接口定义放在单独的项目中(比如“MyInterfaces”),并从EF项目中引用此项目:

public interface IThing
{
   int ID{get;set;}
   string Data{get;set;}
}
数据传输对象 同时,在Interfaces项目中创建一个具体的实现数据传输对象:

project-models
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;}
}
数据访问层 现在,您可以创建一个数据访问层项目,该项目引用您的实体框架和接口项目,并创建某种类,该类的任务是为iThing请求提供服务

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接口上实现自己的功能,但重新使用它只是为了节省时间)

收尾

我提到了这只是一个推动