asp.net-mvc ServiceStack 新服务并排 ASP.NET MVC 网站

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15368257/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 02:38:49  来源:igfitidea点击:

ServiceStack new service side by side ASP.NET MVC website

asp.net-mvcservicestack

提问by mare

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

在ServiceStack的示例中,我没有看到一个应用程序首先是 ASP.NET MVC 网站,然后是 ServiceStack 服务。

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

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

Let's say we have a model of Productwhich gets persisted into a document DB. Let's assume we have a viewmodel of ProductViewModelwhich gets mapped from Productand display within MVC Razor View/PartialView.

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

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.

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

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

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

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

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

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

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

Like so ProductRequestResponse : ProductViewModel?

像这样ProductRequestResponse : ProductViewModel

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).

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

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.

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

Another thing:

另一件事:

If you take a look at this example https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/ServiceStack.MovieRest/MovieService.cs

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

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

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

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 Directorproperty and yet another service (MoviesByDirector) for it?

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

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?

我认为样本应该面向一种服务。与电影有关的一切都需要集中在一个屋檐下。如何使用 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;
    }
}

回答by mythz

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.

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

DTOs are Best practices for remote services

DTO 是远程服务的最佳实践

In following of Martin Fowler's recommendation for using DTOs(Data Transfer Objects) for remote services (MSDN), ServiceStackencourages 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.

遵循Martin Fowler对远程服务 ( MSDN)使用 DTO(数据传输对象)的建议ServiceStack鼓励使用干净、未受污染的 POCO 来定义明确定义的合同,该合同应保持在很大程度上实现和无依赖关系。 dll。这样做的好处是,您可以在C#/.NET 客户端中按原样重用用于定义服务的类型化 DTO - 提供端到端类型化 API,而无需使用任何代码 - gen 或其他人造机械。

DRY vs Intent

干与意图

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.

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

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.

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

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.

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

Using ServiceStack's Built-in auto-mapping

使用 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 AutoMapperor using ServiceStack's built-in Auto Mapping support, e.g:

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

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

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

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

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

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

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

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

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

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

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

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

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

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:

当映射逻辑变得更加复杂时,我们喜欢使用扩展方法来保持代码 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;
    }
}

Which is now easily consumable with just:

现在只需:

var dto = viewModel.ToDto();

回答by Boris B.

If you are not tied specifically to ServiceStack and just want "fully functional service to support programmatic clients ... with what we already have", you could try the following: Have your controllers return either a ViewResultor a JsonResultbased on the request's accept header - Request.AcceptTypes.Contains("text/html")or Request.AcceptTypes.Contains("application/json").

如果您没有专门绑定到 ServiceStack 并且只是想要“支持程序化客户端的功能齐全的服务......使用我们已经拥有的服务”,您可以尝试以下操作:让您的控制器根据请求的接受标头返回 aViewResult或 a JsonResult-Request.AcceptTypes.Contains("text/html")Request.AcceptTypes.Contains("application/json")

Both ViewResultand JsonResultare ActionResult, so the signature of actions remains the same, and both View()and Json()accept a ViewModel. Furthermore, if you have a ControllerBase you can make a base method (for example protected ActionResult RespondWith(Object viewModel)) which calls either View() or Json() so the change to existing code is minimal.

这两个ViewResultJsonResultActionResult,这样的行动的签名仍然是相同的,都View()Json()接受视图模型。此外,如果您有一个 ControllerBase,您可以创建一个protected ActionResult RespondWith(Object viewModel)调用 View() 或 Json()的基本方法(例如),因此对现有代码的更改最小。

Of course, if your ViewModels are not pure (i.e. have some html-specific stuff or you rely on some ViewBag magic) then it's a little more work. And you won't get SOAP or other binding types provided by ServiceStack, but if your goal is to support a JSON data interface with minimal code changes to the existing MVC app then this could be a solution.

当然,如果你的 ViewModels 不是纯的(即有一些特定于 html 的东西或者你依赖一些 ViewBag 魔法)那么它需要更多的工作。您不会获得 ServiceStack 提供的 SOAP 或其他绑定类型,但如果您的目标是支持 JSON 数据接口,并对现有 MVC 应用程序进行最少的代码更改,那么这可能是一个解决方案。

Lp

脂蛋白