如何使ServiceStack与现有的MVC / Service / Repository模式一起工作

时间:2013-09-15 05:45:05

标签: c# servicestack service-layer

我试图绕过ServiceStack并利用它来展示RESTful服务。

我目前正在使用MVC / Service / Repository / UnitOfWork类型模式,其中获取客户的基本操作可能如下所示:

MVC Controller Action --> Service Method --> Repository --> SQL Server

我的问题是:

  1. 我的SS服务有什么回报?域对象?或者我是否返回DTO     有一组客户?如果是这样,那是什么     顾客?域对象或视图模型或??
  2. SS服务应该替换我的服务层吗?
  3. 我在这里采取了错误的做法吗?
  4. 我想我有点困惑如何让所有这些并存。

    域对象

    public class Customer
    {
        public int Id {get;set;}
        public string FirstName {get;set;}
        public string LastName {get;set;}
    }
    

    查看模型

    public class CustomerViewModel
    {
        public int Id {get;set;}
        public string FirstName {get;set;}
        ....
    }
    

    控制器

    public class CustomersController : Controller
    {
        ICustomerService customerService;
    
        public CustomersController(ICustomerService customerService)
        {
            this.customerService = customerService;
        }
    
        public ActionResult Search(SearchViewModel model)
        {
            var model = new CustomersViewModel() {
                Customers = customerService.GetCustomersByLastName(model.LastName); // AutoMap these domain objects to a view model here
            };
    
            return View(model);
        }
    }
    

    服务

    public class CustomerService : ICustomerService
    {
        IRepository<Customer> customerRepo;
    
        public CustomerService(IRepository<Customer> customerRepo)
        {
            this.customerRepo = customerRepo;
        }
    
        public IEnumerable<Customer> GetCustomersByLastName(string lastName)
        {
            return customerRepo.Query().Where(x => x.LastName.StartsWith(lastName));
        }
    }
    

1 个答案:

答案 0 :(得分:3)

首先,这只是个人偏好,我将摆脱您的存储库层,只是直接从服务操作访问/验证您的数据。如果您所做的只是传递参数,那么拥有所有这些额外的层是毫无意义的。

回答你的问题:

1)您的服务应该返回DTO(source),您提到您正在使用MVC应用程序,因此请确保您在操作中使用IReturn接口,这将允许您可以在控制器操作中执行var customers = client.Get(new GetCustomers());之类的操作,请参阅here。您如何使用DTO,如果您愿意,可以将其用作ViewModel,如果您需要其他来源的其他属性,则可以创建单独的ViewModel。

2)是的,ServiceStack是您应用程序中的服务层,通常您将通过该层进行所有交互,不需要所有这些不同的层(上面我的第一点),为此,它看起来好像这个应用程序的架构比它需要的更复杂..

3)我认为是的,你似乎在考虑你的应用,切掉所有这些层

就上述示例而言,遵循建议here。我会做这样的事情:

项目结构(这些可以是一个项目中的文件夹,也可以根据应用程序的大小分成不同的项目:)

  

虽然对于只有少量服务的小型项目,可以将所有内容都放在一个项目中,并根据需要简单地扩展您的架构。

- SamProject.Web
    App_Start
        AppHost.cs
    Controllers
        CustomerController.cs

- SamProject.ServiceInterface 
    Services
        CustomersService.cs
    Translators                 // Mappings from Domain Object > DTO
        CustomersTranslator.cs

- SamProject.Data               // Assumes using EF
    CustomersContext.cs
    Customer.cs

- SamProject.ServiceModel     
    Operations               
        CustomersService            
            GetCustomers.cs
            GetCustomer.cs
            CreateCustomer.cs           
    Resources
        CustomerDTO.cs

<强>代码

DTO:

public class CustomerDTO
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

操作:

[Route("/customers/{Id}")]
public class GetCustomer : IReturn<CustomerDTO>
{
    public int Id { get; set; }
}

[Route("/customers")]
public class GetCustomers : IReturn<IEnumerable<CustomerDTO>>
{
    public string LastName { get; set; }
}

服务:

public class CustomersService : Service
{
    private readonly CustomerContext _dbCustomerContext;

    public CustomersService(CustomerContext dbCustomerContext)
    {
        _dbCustomerContext = dbCustomerContext;
    }

    public object Get(GetCustomer request)
    {
        return _dbCustomerContext.Customers
               .FirstOrDefault(c => c.Id == request.Id)
               .Select(c => c.Translate());
    }

    public object Get(GetCustomers request)
    {
        if (string.IsNullOrEmpty(request.LastName))
        {
            return _dbCustomerContext.Customers.ToList()
                   .Select(c => c.Translate());
        }

        return _dbCustomerContext.Customers
               .Where(c => c.LastName == request.LastName).ToList()
               .Select(c => c.Translate());
    }
}

控制器:

public class CustomersController : Controller
{
    private readonly JsonServiceClient _client;

    public CustomersController(JsonServiceClient client)
    {
        _client = client;
    }

    public ActionResult Search(SearchViewModel model)
    {
        var customers = _client.Get(new GetCustomers
        {
            LastName = model.LastName
        });

        return View(customers);
    }

}

备注

  • 我喜欢将DTO视为资源
  • 我喜欢根据代码的意图将我的代码分离成结构化的文件夹结构,这只会在以后代码库变得更大但后者在中小型应用程序中帮助你可能不需要像这样分开你的代码
  • 我没有谈过其他功能,例如日志记录,验证,IoC(只是展示具体的实现)等。
  • Translate是一种扩展方法,可以在Translators中使用,也可以使用内置的translator
  • ServiceModel我确实有一个明确定义的文件夹结构,但是,我的服务操作的命名空间只是SamProject.ServiceModel而不是SamProject.ServiceModel.Operations.CustomersService。但是,我的资源位于SamProject.ServiceModel.Resources名称空间。