ServiceStack新服务并行ASP.NET MVC网站

mar*_*are 28 asp.net-mvc servicestack

在ServiceStack 的示例中,我没有首先看到ASP.NET MVC网站的单个应用程序,然后将ServiceStack服务放在第二位.

我们来看一个非常简单的ASP.NET MVC Web应用程序,它通过Views呈现产品.它使用控制器,视图,模型和视图模型.

假设我们有一个模型Product被持久存储到文档DB中.假设我们有一个viewmodel,ProductViewModel它从ProductMVC Razor View/PartialView中映射并显示.

所以这是一个网络方面的东西..现在让我们假设我们想要添加一个服务返回产品到各种客户端,如Windows 8应用程序.

请求/响应类是否应该与我们已有的完全断开?我们ProductViewModel可能已经包含了我们想要从服务中返回的所有内容.

既然我们已经有了Product(模型类),我们就不能Product在API命名空间中拥有另一个类.我们可以但是这会使事情变得不清楚,我想避免这种情况.

那么,我们应该在API命名空间中引入独立ProductRequest类和ProductRequestResponse(继承ProductViewModel)类吗?

像这样ProductRequestResponse : ProductViewModel

我所说的是,我们已经拥有Model和ViewModel类,并为SS服务构建Request和Response类,我们必须创建另外两个文件,主要是通过复制我们已有的类中的所有内容.这对我来说看起来并不干净,它可能会遵循关注点分离指南,但DRY也很重要,实际上不仅仅是分离所有内容(将所有内容分开导致代码重复).

我希望看到的是一个已经建立了Web应用程序的情况,它目前具有Models和ViewModel,并返回适当的视图以便在Web上显示,但是可以扩展为支持程​​序化客户端的全功能服务?就像AJAX客户端......以及我们已经拥有的东西.

另一件事:

如果您看一下这个例子,请访问https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/ServiceStack.MovieRest/MovieService.cs

你会看到有MovieRequest类和MoviesRequest类(一个用于单个电影请求,另一个用于电影列表).因此,也有两个服务,MovieService并且MoviesService,一个交易与一个单一的电影,另一部分用于电影的流派的请求.

现在,虽然我喜欢SS服务方法而且我认为它是正确的,但我不喜欢这种分离只是因为请求的类型.如果我想要导演的电影怎么办?我是否会发明另一个具有Director属性的请求类以及另一个服务(MoviesByDirector)?

我认为样本应该面向一项服务.所有必须处理电影的东西都需要在一个屋檐下.如何通过ServiceStack实现这一目标?

public class ProductsService : Service
{
    private readonly IDocumentSession _session;
    private readonly ProductsHelperService _productsHelperService;
    private readonly ProductCategorizationHelperService _productCategorization;

    public class ProductRequest : IReturn<ProductRequestResponse>
    {
        public int Id { get; set; }
    }

    // Does this make sense? 
    // Please note, we use ProductViewModel in our Views and it holds everything we'd want in service response also
    public class ProductRequestResponse : ProductViewModel
    {
    }

    public ProductRequestResponse GetProducts(ProductRequest request)
    {
        ProductRequestResponse response = null;
        if (request.Id >= 0)
        {
            var product = _session.Load<Product>(request.Id);
            response.InjectFrom(product);
        }
        return response;
    }
}
Run Code Online (Sandbox Code Playgroud)

myt*_*thz 69

服务层是您最重要的合同

您可以在整个系统中创建的最重要的界面是面向外部的服务合同,这是您的服务或应用程序的消费者将绑定到的,即现有的呼叫站点通常不会随您的代码一起更新-base - 每个其他模型都是次要的.

DTO是远程服务的最佳实践

在遵循Martin Fowler关于将DTO(数据传输对象)用于远程服务(MSDN)的建议之后,ServiceStack鼓励使用干净,无污染的POCO来定义明确定义的合同,该合同应保留在很大程度上实现且无依赖性. DLL.这样做的好处使您能够重新使用用于在C#/ .NET客户端中定义服务的类型DTO - 提供端到端类型的API而无需使用任何代码 - gen或其他人造机械.

DRY vs Intent

保持干燥不应该与明确说明意图相混淆,你应该避免试图干掉或隐藏在继承,魔法属性或任何其他机制背后.拥有干净,定义明确的DTO提供了一个参考源,任何人都可以查看每个服务接受和返回的内容,它允许您的客户端和服务器开发人员立即开始工作并绑定到外部服务模型而无需实现写完了.

保持DTO分离还使您可以自由地从内部重新实现实现,而不会破坏外部客户端,即您的服务开始缓存响应或利用NoSQL解决方案来填充您的响应.

它还提供了用于创建自动生成的元数据页面,示例响应,Swagger支持,XSD,WSDL等的权威来源(未在应用逻辑中泄露或耦合).

使用ServiceStack的内置自动映射

虽然我们鼓励保留单独的DTO模型,但您不需要维护自己的手动映射,因为您可以使用AutoMapper之类的映射器或使用ServiceStack的内置Auto Mapping支持,例如:

创建一个新的DTO实例,在viewModel上填充匹配的属性:

var dto = viewModel.ConvertTo<MyDto>();
Run Code Online (Sandbox Code Playgroud)

初始化DTO并使用视图模型上的匹配属性填充它:

var dto = new MyDto { A = 1, B = 2 }.PopulateWith(viewModel);
Run Code Online (Sandbox Code Playgroud)

初始化DTO并使用视图模型上的非默认匹配属性填充它:

var dto = new MyDto { A = 1, B = 2 }.PopulateWithNonDefaultValues(viewModel);
Run Code Online (Sandbox Code Playgroud)

初始化DTO并使用在视图模型上使用Attr属性注释的匹配属性填充它:

var dto = new MyDto { A=1 }.PopulateFromPropertiesWithAttribute<Attr>(viewModel);
Run Code Online (Sandbox Code Playgroud)

当映射逻辑变得更复杂时,我们喜欢使用扩展方法来保持代码DRY并将映射保存在一个易于从应用程序中消耗的地方,例如:

public static class MappingExtensions
{
    public static MyDto ToDto(this MyViewModel viewModel)
    {
        var dto = viewModel.ConvertTo<MyDto>();
        dto.Items = viewModel.Items.ConvertAll(x => x.ToDto());
        dto.CalculatedProperty = Calculate(viewModel.Seed);
        return dto;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在只需使用以下产品即可轻松消费:

var dto = viewModel.ToDto();
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你在我试图解释这个时给我提供一些东西来向人们展示. (8认同)
  • 没有什么能阻止您将视图模型重新用作请求DTO.它可能不是被禁止或推荐的方法,但请求DTO只是POCO,任何C#类都可以用作请求DTO.但是,正如@mythz建议的那样(以及我个人的经验),你想把这些东西分开.您可能认为重复会导致令人头疼,但尝试让您的视图模型执行所有操作会导致更多. (4认同)