期待已久的中间件:Microsoft .NET RIA Services (转贴)

来源:互联网 发布:mac 显示隐藏 编辑:程序博客网 时间:2024/05/09 04:04

 

(很好的一个产品概述, 转自 http://www.nikhilk.net/ 的博客:.NET RIA Services: From Vision to Architecture. 有了这个中间件,程序商业逻辑层可以100%重用了。那么Silverlight和WPF的应用程序兼容性应该高于95%了)


.NET RIA Services is now public. And folks at MIX generally loved what we're doing in this space, which is a promising start. We don't yet have a great landing page for the technology but here is what the download page currently has to say:

Microsoft .NET RIA Services simplifies the traditional n-tier application pattern by bringing together the ASP.NET and Silverlight platforms. RIA Services provides a pattern to write application logic that runs on the mid-tier and controls access to data for queries, changes and custom operations. It also provides end-to-end support for common tasks such as data validation, authentication and roles by integrating with Silverlight components on the client and ASP.NET on the mid-tier.
A rather brief summary. There is also a walkthrough I recommend checking out to get a first hand feel at the basic usage. In this post, I want to share some of the thoughts and architectural concepts behind the bits. This is going to turn into a super long post, but I hope it is still a useful read, and provides insight to both evaluate and hopefully appreciate the bits.

 

As we looked at Silverlight planning, we realized RIA development is simply hard. There are too many moving pieces to manually stitch together between the client and the server. There are too many things that are un-natural, yet the norm, starting with the forced n-tier (many developers are used to writing 2-tier apps), async (when sync is the norm), dealing with latency (doing so incorrectly has the potential to break end-user experience), figuring out how to be less chatty, dealing with validation, conflicts, disconnected or occasionally connected scenarios, performing authentication and sharing user state across client and server, the list goes on and on...

We wanted to simplify RIA development... and bring back productivity for mainstream development, in much the same way that ASP.NET 1.0 provided client app developers a productive platform for developing Web apps. The pendulum has swung, and it is time to simplify RIA-style client development.

For many reasons, I like to think of .NET RIA Services and what we are doing as RAD for RIA.

Seeing RIAs in a New Light

The biggest value proposition that .NET RIA Services brings to the table is a new unified look at the client and server as two halves of the same logical application. The two halves aren't two separate applications. Simply speaking, we wanted to make development as simple as 2-tier apps, without sacrificing good n-tier design or compromising on fundamentals.

Lets look at the anatomy of a classic Web application (and most Ajax apps aren't significantly different).

Classic Web Application

The web application on the middle tier talks to one or more back-end databases and services. It contains a data model and data access layer defining what the app works over, application logic that constrains what can be done using the application and finally some presentation logic, typically something that projects HTML for rendering in a browser. Most of the app resides on the server, and that simplifies things; accessing different bits of functionality is as simple as vanilla method calls.

With a RIA, most of the presentation logic moves to the client to improve the UX and to make effective use of local state. The result is additional work for the developer: defining a full-fledged services layer, new types and contracts to share etc. and continually evolving them as the app evolves on either end.

We see a subtly different picture - a broader single box called the Rich Internet Application. A RIA isn't just a client app, but an "Internet" app that includes a server component.

Rich Internet Application

The presentation tier is separated by a network, but .NET RIA Services steps in to provide the plumbing behind the scenes to preserve a 2-tier feel to the overall codebase. Peel back a layer, and underneath the covers, you'll see familiar building blocks: the goodness of services, and open/standard protocols (more on that below). They're simply implementation detail, that you don't have to focus on as the high order bit. Instead you get to focus on your application's logic and user interface.

When you look at the complete picture that includes other applications that version and evolve independently, concrete services with well-thought out and explicit contracts are still very much recommended. That doesn't change with .NET RIA Services.

The network in between the client and server is still very much real. Our goal isn't to hide that with some magic. However we want to address that trust boundary and point of latency by incorporating those factors into the programming model and making them natural, and simplifying the associated tooling.

What this fresh look at RIA lets us do:

  • Share behavior, application semantics, metadata, and even implementation rather than just contract between tiers. Its all within the bounds of the same app. Why do things twice?
  • Gear our tooling to address what you're building - a RIA. There is a lot more we have to do to get to nirvana here. Over time...

 

 

A Concrete, End-to-End, Application Pattern

I should preface this section by saying that there isn't a single valid pattern. Lots of folks think there is only one pattern that works. I think otherwise. And consequently what we have here will work for some applications, not all. We do have lots of extensibility hooks for those wishing to extend the pattern or apply it to their specific scenarios and perspectives.

The end-to-end application pattern revolves around data and domain-specific logic. What is interesting is we're making what a lot of application developers already do more concrete, rather than leaving it as an exercise for developers, so that it can be tooled and made more mainstream.

Using the example from my MIX demo, I have a simple data model with Product and Category entities.

DomainService + DomainContext Pattern

The first part of our pattern is to write a DomainService class. This represents your application domain, your application logic, or business logic. It surfaces the set of data a client can see, which might be DAL types, or projection types invented specifically for use by the presentation tier, or a combination thereof. It also surfaces a set of operations: both CRUD-based and custom domain-specific operations. It also specifies rules around the data and the operations such as authorization and validation. Finally it encapsulates any DAL-specific nuances. A DomainService is optimized to be stateless - to respond to query requests and to change set processing requests.

The second part of the pattern is what we generate - the client-side data model - in a DomainContext class. This class represents the view of what the client can see. It contains lists of objects, one for each type exposed to the client, and it contains a set of load methods that roughly correspond to the queries exposed on the service. These load methods can be used to load objects into the corresponding lists. The individual objects and lists track changes and raise change notifications. The DomainContext can extract all the changes, create a change set and submit it to the service for processing and commiting. A DomainContext is optimized for taking advantage of the stateful environment and to be a well-behaved citizen in a binding-centric presentation technology such as Silverlight or WPF.

When you peel a layer, you'll see that the infrastructure is built on familiar building blocks of services and proxies and deriving the qualities of service-based design.

Infrastructure behind a DomainService and DomainContext

The only difference is since you're within the bounds of within an application, the infrastructure is closer to plumbing that is provided through tooling and runtime framework functionality. Specifically the DataService on the server is an honest to goodness HTTP endpoint speaking either REST or SOAP, using either XML or JSON (implemented in the longer term via WCF and ADO.NET Data Services). On the client, the DomainContext serves as a specialized proxy that is aware of the underlying data semantics.

 

A Scalable Pattern

The DomainService pattern for writing your application logic itself isn't restricted to just RIAs written in Silverlight connecting to some back-end relational database. That is a single slice of a bigger story.

DomainService + DomainContext Pattern Scale Out

The DomainService pattern can work against a variety of data sources from plain old CLR types, that might be manufactured from thin air, retrieved from cloud storage, such as Azure, or retrieved from a database, but through a repository layer. In the bits we released, we support Linq To Sql and Linq To Entities. In my demos, I showed Azure and CLR types. We plan to share more details on how to work with a greater variety of back-end data access technologies.

On the other side, we have Silverlight and WPF representing a .NET to .NET slice of the story. However, the infrastructure on top of DomainService speaks in an open/standard/RESTful manner. As such script/Ajax clients using any Ajax framework can work with the middle tier. Server-side rendering-based applications using Web Forms or MVC can make use of the same application logic. And finally, for non-UI clients, such as other applications, one can build a services layer to project the data and operations via a SOAP or REST interface. My MIX demo bits contain a sample of Ajax and ASP.NET usages.

The DomainService you build is a concrete and tangible asset in your overall application that can be reused and be a central point for abstracting your data layer from the rest of the system. As such it might be interesting to ensure high quality and maintainability through a set of unit tests. In fact, a unit test is simply another client of the application logic. My MIX demo bits contained a sample of that.

 

A Pattern Beyond CRUD

Application Services and Patterns behyond CRUDThe final piece about this pattern I want to cover in this already long article is how this ties in with our application services story, and how they address concrete application scenarios while building on this foundation of DomainService+DomainContext and CRUD. These application services will ratchet up the productivity level one more notch, by providing out-of-the-box solutions for common tasks and scenarios, while being extensible and pluggable thanks to the underlying foundation.

Lets look at the one application service we ship out of the box - Authentication. Specifically this takes care of logging in, enabling role-based authorization and managing user settings. And it does so on both the server and the client - remember, single application, single set of patterns that apply on both tiers. Authentication derives from DomainService. The entity or data it exposes is a User object. In addition to getting the current user, it exposes operations such as Login and Logout. However the API that authentication itself exposes doesn't have a CRUD feel. Instead it looks like a specific API tailored for the specific scenario of authentication.

In similar vein, we might see other application services such as UserRegistration, Diagnostics, Analytics, ApplicationWhiteboard etc. Each offers a domain-specific API, but would build on the foundation of DomainService+DomainContext and CRUD.

 

Summary

Despite being prescriptive, I think we have a very flexible technology built on building blocks that can be replaced. A small set of examples:

 

  • For example, you could write your own explicit service on top of the application logic or DomainService pattern, and you could create an explicit service reference in your client, if you prefer to be explicit across tiers, rather than using all of the underlying infrastructure.
  • You could plug in your own back-end store if the ones we support out-of-the box don't match your needs. For example, you could plug in a rich domain model.
  • You could decide how much of the DAL you want to expose or how little, by instead constructing an explicit set of presentation types.

 

We still have a ways to go. In many ways what was shown is just the first step. There are still missing pieces, and new areas we need to tackle. This is where you come in - with your feedback upon evaluating the technology further.