ServiceStack新服务并排ASP.NET MVC网站
在ServiceStack的示例中 ,我没有看到一个单独的应用程序,它先是ASP.NET MVC网站,然后是ServiceStack服务。
我们来看一个非常简单的通过Views呈现产品的ASP.NET MVC Web应用程序。 它使用控制器,视图,模型和视图模型。
比方说,我们有一个Product
的模型被持久化到文档数据库中。 假设我们有一个ProductViewModel
的视图模型,它从Product
映射到MVC Razor View / PartialView。
所以这是一个networking的一面..现在让我们假设我们想要添加一个服务返回产品的Windows 8应用程序的各种客户端。
请求/响应类应该与我们已经有的完全断开? 我们的ProductViewModel
可能已经包含了我们想从服务返回的所有东西。
由于我们已经有Product
(模型类),所以我们不能在API命名空间中拥有另一个Product
类。我们可以但是这使得事情不清楚,我想避免这种情况。
那么,我们是否应该在API命名空间中引入独立的ProductRequest
类和ProductRequestResponse
(inheritanceProductViewModel)类?
像这样ProductRequestResponse : ProductViewModel
?
我所说的是,我们已经有了Model和ViewModel类,并且为SS服务构buildRequest和Response类,我们将不得不创build另外两个文件,主要是通过从我们已有的类复制所有东西。 这对我来说看起来并不干,它可能遵循关注点分离的指导原则,但DRY也很重要,实际上不是分隔所有东西(分隔所有东西导致代码重复)。
我想看到的情况是已经创build了一个Web应用程序,它目前具有Models和ViewModel,并返回适当的Views以显示在Web上,但是可以扩展为一个function完备的服务来支持程序化客户端? 像AJAX客户端等…我们已经有了。
另一件事:
如果你看看这个例子https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/ServiceStack.MovieRest/MovieService.cs
你会看到有Movie
Request类和Movies
Request类(一个用于单个电影请求,另一个用于电影列表)。 因此,也有两个服务, MovieService
和MoviesService
,一个处理单个电影的请求,另一个处理电影stream派。
现在,虽然我喜欢SS的服务方式,但我认为这是正确的,但由于请求的types,我不喜欢这种分离。 如果我想要导演的电影呢? 我会发明另一个具有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; } }
服务层是您最重要的合同
您可以在整个系统中创build的最重要的接口是外部服务合同,这就是您的服务或应用程序的使用者将绑定到的内容,即现有的通常不会随您的代码一起更新的呼叫站点基础 – 每隔一个模型是次要的。
DTO是远程服务的最佳实践
在Martin Fowler关于使用远程服务的DTO (数据传输对象)( MSDN )的build议之后, ServiceStack鼓励使用干净的,未被污染的POCO来定义一个明确定义的合同,并保持在一个大部分的实现和依赖关系。 DLL。 这样做的好处是,您可以重新使用types化的DTO来定义您的服务,就像在您的C#/ .NET客户端中一样 – 提供端到端的types化API,而无需使用任何代码 – gen或其他人造机器。
DRY vs意图
保持干燥不应该与明确的意图说明混淆,你应该避免试图干燥或隐藏在inheritance ,魔法属性或任何其他机制。 清洁的,定义明确的DTO提供了一个单一的参考来源,任何人都可以查看每个服务接受和返回的内容,它允许客户端和服务器开发人员立即开始工作并绑定到外部服务模型,而无需实现已被写入。
保持DTO分离的同时,还可以自由地从内部重新实现实现,而不会破坏外部客户端,即您的服务开始caching响应或利用NoSQL解决scheme来填充响应。
它还提供了用于创build自动生成的元数据页面,示例响应,Swagger支持,XSD,WSDL等的权威来源(不会泄漏或耦合到您的应用程序逻辑中)。
使用ServiceStack的内置自动映射
虽然我们鼓励保留单独的DTO模型,但您不需要维护自己的手动映射,因为您可以使用像AutoMapper这样的映射器或使用ServiceStack内置的自动映射支持,例如:
创build一个新的DTO实例,在viewModel上填充匹配的属性:
var dto = viewModel.ConvertTo<MyDto>();
初始化DTO并使用视图模型上的匹配属性填充它:
var dto = new MyDto { A = 1, B = 2 }.PopulateWith(viewModel);
初始化DTO并在视图模型上使用非默认的匹配属性填充它:
var dto = new MyDto { A = 1, B = 2 }.PopulateWithNonDefaultValues(viewModel);
初始化DTO并使用在视图模型上使用Attr属性注释的匹配属性填充它:
var dto = new MyDto { A=1 }.PopulateFromPropertiesWithAttribute<Attr>(viewModel);
当映射逻辑变得更复杂时,我们喜欢使用扩展方法来保持代码干燥,并将映射维护在应用程序内容易消耗的某个位置,例如:
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绑定,只想要“function齐全的服务来支持程序化客户端…我们已经有了”,你可以尝试以下方法:让你的控制器根据请求的接受返回ViewResult
或者JsonResult
头文件 – Request.AcceptTypes.Contains("text/html")
或Request.AcceptTypes.Contains("application/json")
。
ViewResult
和JsonResult
都是ActionResult
,所以动作的签名保持不变, View()
和Json()
接受一个ViewModel。 此外,如果你有一个ControllerBase,你可以调用View()或者Json()方法来调用一个基本方法(例如protected ActionResult RespondWith(Object viewModel)
),这样对现有代码的改变是最小的。
当然,如果你的ViewModel不是纯粹的(例如,有一些特定于HTML的东西,或者你依赖一些ViewBag的魔法),那么这是一个更多的工作。 而且你不会得到由ServiceStack提供的SOAP或其他绑定types,但是如果你的目标是通过对现有的MVC应用程序的最小代码改变来支持JSON数据接口,那么这可能是一个解决scheme。
唱片