ServiceStack 新服务并排 ASP.NET MVC 网站 [英] ServiceStack new service side by side ASP.NET MVC website

查看:33
本文介绍了ServiceStack 新服务并排 ASP.NET MVC 网站的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 ServiceStack 的 examples 中,我没有看到一个 ASP.NET 应用程序先做MVC网站,再做ServiceStack服务.

In the examples for ServiceStack I don't see a single application that is ASP.NET MVC website first and then made ServiceStack service second.

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

Let's take a very simple ASP.NET MVC web application that renders products through Views. It uses controllers, views, models and viewmodels.

假设我们有一个 Product 模型,它被持久化到文档数据库中.假设我们有一个 ProductViewModel 的视图模型,它从 Product 映射并显示在 MVC Razor View/PartialView 中.

Let's say we have a model of Product which gets persisted into a document DB. Let's assume we have a viewmodel of ProductViewModel which gets mapped from Product and display within MVC Razor View/PartialView.

所以这是一个 Web 方面的事情..现在让我们假设我们要添加一项服务,将产品返回给各种客户端,例如 Windows 8 应用程序.

so this is a web side of things..now let's assume we want to add a service returning products to various clients like the Windows 8 applications.

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

Should the request/response classes be completely disconnected from what we already have? Our ProductViewModel might already contain everything we want to return from the service.

因为我们已经有了 Product(模型类),我们不能在 API 命名空间中再有另一个 Product 类..我们可以,但这让事情变得不清楚,我想避免这种情况.

Since we already have Product (model class) we can't have another Product class in the API namespace..well we could but that makes things unclear and I'd like to avoid that.

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

So, should we introduce standalone ProductRequest class and ProductRequestResponse (inherits ProductViewModel) class in the API namespace?

像这样 ProductRequestResponse : ProductViewModel?

我的意思是,我们已经有了 Model 和 ViewModel 类,要为 SS 服务构造请求和响应类,我们必须创建另外两个文件,主要是通过从我们已有的类中复制所有内容.这在我看来并不 DRY,它可能遵循关注点分离准则,但 DRY 也很重要,实际上不仅仅是分离所有内容(分离所有内容会导致代码重复).

What i'm saying is, we already have the Model and ViewModel classes and to construct Request and Response classes for the SS service we would have to create another two files, mostly by copying everything from the classes we already have. This doesn't look DRY to me, it might follow the separation of concerns guidelines but DRY is important too, actually more than separating everything (separating everything leads to duplication of code).

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

What I would like to see is a case where a web application has already been made, it currently features Models and ViewModels and returns the appropriate Views for display on the Web but can be extended into a fully functional service to support programmatic clients? Like AJAX clients etc...with what we already have.

另一件事:

如果你看看这个例子 https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/ServiceStack.MovieRest/MovieService.cs

你会看到有 Movie 请求类和 Movies 请求类(一个用于单个电影请求,另一个用于电影列表).因此,还有两个服务,MovieServiceMoviesService,一个处理单个电影的请求,另一个处理电影类型的请求.

you will see there is Movie Request class and Movies Request class (one for single movie request, the other one for a list of movies). As such, there are also two services, MovieService and MoviesService, one dealing with requests for a single movie, the other one for a genre of movies.

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

Now, while I like SS approach to services and I think it is the right one, I don't like this sort of separation merely because of the type of request. What if I wanted movies by director? Would I be inventing yet another request class having a Director property and yet another service (MoviesByDirector) for it?

我认为样本应该面向一种服务.与电影有关的一切都需要集中在一个屋檐下.如何使用 ServiceStack 实现这一目标?

I think the samples should be oriented towards one service. Everything that has to deal with movies need to be under one roof. How does one achieve that with 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;
    }
}

推荐答案

服务层是你最重要的契约

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

The Service Layer is your most important Contract

The most important interface that you can ever create in your entire system is your external facing service contract, this is what consumers of your service or application will bind to, i.e. the existing call-sites that often won't get updated along with your code-base - every other model is secondary.

遵循 Martin Fowler 对使用 DTO 的建议(数据传输对象)进行远程服务(MSDN)、ServiceStack 鼓励使用干净、未受污染的 POCO 来定义明确定义的合约,该合约应保存在主要实现和无依赖关系的 .dll 中.这样做的好处是,您可以在 C#/.NET 客户端 - 在不使用任何代码生成或其他人工机器的情况下提供端到端类型的 API.

In following of Martin Fowler's recommendation for using DTOs (Data Transfer Objects) for remote services (MSDN), ServiceStack encourages the use of clean, untainted POCOs to define a well-defined contract with that should kept in a largely implementation and dependency-free .dll. The benefits of this allows you to be able to re-use typed DTOs used to define your services with, as-is, in your C#/.NET clients - providing an end-to-end typed API without the use of any code-gen or other artificial machinery.

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

Keeping things DRY should not be confused with clearly stating of intent, which you should avoid trying to DRY or hide behind inheritance, magic properties or any other mechanism. Having clean, well-defined DTOs provides a single source of reference that anyone can look at to see what each service accepts and returns, it allows your client and server developers to start their work straight away and bind to the external service models without the implementation having been written.

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

Keeping the DTOs separated also gives you the freedom to re-factor the implementation from within without breaking external clients, i.e. your service starts to cache responses or leverages a NoSQL solution to populate your responses with.

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

It's also provides the authoritative source (that's not leaked or coupled inside your app logic) that's used to create the auto-generated metadata pages, example responses, Swagger support, XSDs, WSDLs, etc.

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

Whilst we encourage keeping separate DTO models, you don't need to maintain your own manual mapping as you can use a mapper like AutoMapper or using ServiceStack's built-in Auto Mapping support, e.g:

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

Create a new DTO instance, populated with matching properties on viewModel:

var dto = viewModel.ConvertTo<MyDto>();

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

Initialize DTO and populate it with matching properties on a view model:

var dto = new MyDto { A = 1, B = 2 }.PopulateWith(viewModel);

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

Initialize DTO and populate it with non-default matching properties on a view model:

var dto = new MyDto { A = 1, B = 2 }.PopulateWithNonDefaultValues(viewModel);

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

Initialize DTO and populate it with matching properties that are annotated with the Attr Attribute on a view model:

var dto = new MyDto { A=1 }.PopulateFromPropertiesWithAttribute<Attr>(viewModel);

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

When mapping logic becomes more complicated we like to use extension methods to keep code DRY and maintain the mapping in one place that's easily consumable from within your application, e.g:

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;
    }
}

现在只需:

var dto = viewModel.ToDto();

这篇关于ServiceStack 新服务并排 ASP.NET MVC 网站的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆