WCF RIA Services Domain Serive的生命周期和数据交互

前几天看到几个人都在说WCF RIA Services的添加记录有问题,今天看到一篇好文章给大家转过来,对你了解它的交互性会很有帮助。

作者是个很牛逼的人,大家可以到他的博客看看,

http://weblogs.asp.net/fredriknormen/default.aspx

 

Some questions that pops up about WCF RIA Services is how to enable transactions. So I decided to write a blog post about it, but to not make this post just a few lines I also decided to write about the DomainService life-cycle so you will know what will happen step-by-step in the DomainService after a DomainContext’s SubmitChanges is called on the client-side.

The following images will show you the part of the DomainService life-cycle when a SubmitChanges takes place:

image

The first thing that will happen is the creation of the DomainService, this is done through a Domain Service Factory, you can read about it here. The Domain Service Factory will make a call to the DomainService Initialize method. Within this method you can for example set the ConnectionString on the ObjectContext’s Connection if you are using the LintToEntitesDomainService, or the DataContext if you are using the LintToSqlDomainService.

Here is an example of changing the ObjectContext’s Connection’s ConnectionString:

[EnableClientAccess()]
public class CustomerDomainService : LinqToEntitiesDomainService<NORTHWNDEntities>
{
     public override void Initialize(DomainServiceContext context)
     {
         this.ObjectContext.Connection.ConnectionString = "";            
         base.Initialize(context);
      }

     ...
}

 

After the Initialization the Submit method of the DomainService will be executed. This method will execute the following DomainService methods in the following order:

1) AuthorizationChangeSet

2) ValidateChangeSet

3) ExecuteChangeSet

4) PersistChangeSet

5) ResolveChangeSet


Note: I will only focus on the virtual method which you can overwrite.

You can override the Submit method and do something before the Submit will take place, and also do things after the Submit is executed, for example do some pre- and post conditions like logging etc.

Note: If you want to log exceptions that will take place during a Submit, it’s recommended that you override the OnError method and log the exception within that method.

public override bool Submit(ChangeSet changeSet)
{
   //do something here pre submit

   var submitResult = base.Submit(changeSet);
            
    //do something here post submit

    return submitResult;
}

 


The base.Submit will make a call to the OnError if there was any error during the process of the Submit method, so it will not take place after the Submit method. There is a try and catch block around all the above mentioned methods within the base.Submit method so if anyone of them will fail the Submit method will make a call to the OnError an then throw the exception up the chain.

Note: The PersistChangeSet methods of the LinqToEntitiesDomainService and LinqToSqlDomainService can also make a call to the OnError method if a concurrency conflict occurs during the persistent of the entities.

As I mentioned earlier the Submit method will make a call to some methods in a specific order, the first method is the AuthorizeChangeSet, but before taking a look at the AuthorizeChangeSet method I will focus on the ChangeSet object, which every xxxxChangeSet methods will take as an argument.

 

updateCustomer.Name = "Jane Doe";

var newCusotmerc = new Customer() { CustomerID = 2, Name = "Fred Doe" };

domainContext.Customers.Add(newCustomer);

domainContext.Customers.Remove(removeCustomer);

domainContext.SubmitChanges();

The ChangeSet’s ChangeSetEntries will have three ChangeSetEntry:


Operation = Insert, Entity = newCustomer

Operation = Update, Entity = updateCustomer

Operation = Delete, Entity = removeCustomer


The Operation property of the ChangeSetEntry has the name of the operation that should take place. A operation method is the method which you add to the DomainService to Insert, Update or Delete an entity. The method use a naming convention where the prefix of the method name is the name of the operation, the method can only take an Entity as argument, here is an example of three operation methods added to the DomainService:

public void InsertCustomer(Customer customer)
        
public void UpdateCustomer(Customer customer)
       
public void DeleteCustomer(Customer customer)

 

The following name can be used for the Insert operation: Insert, Create and Add, or the InsertAttribute on the method if you don’t want to use the naming convention.

The following name can be used for the Update operation: Update. Modify and Edit, or the UpdateAttribute on the method.

The following for the Delete operation: Delete and Remove or the DeleteAttribute.

There is something called a “custom” method. A Custom method can’t return anything and the first argument must be an entity the rest a valid RIA Services type. The name of the method doesn’t matter. Here is an example of a Rebate custom method:


public
void Rebate(Customer customer)


When a “custom” method is called on the client-side, it will not be added to the ChangeSet as a Operation will. Instead it will be added as an EntityAction to the ChangeSet’s Entity.

The Entity property holds the Entity that should be passed to the specific Operation and also the “custom” methods that should be executed.

I will not dig any deeper into the ChangeSet class, it has more properties and method for Entity associations and error etc.

Now to the different xxxxxChangeSet methods.

AuthorizeChangeSet

The AuthorizeChangeSet method is the first method that will be executed when the Submit method is called. This method will validate and see if the current user are allowed to make a call to the DomainService operations. The AuthorizeChangeSet method will iterate through the ChageSet and see if any of the Operations in ChangeSet or the “custom” methods has any of the the AuthorizeAttribute specified (ReuqiredAuthenticationAttribute or RequiredRoleAttrtibute). The AuthorizeAttribute is used to prevent non-authorized user to make a call to an operation method. If the current user isn’t allowed to execute any of the operations in the ChangeSet an exception will be thrown and the OnError method of the DomainService will be called, and the execution of the Submit will ended. Here is an example where the AuthroizateAttribute is used:

[RequiresAuthentication(), RequiresRole("Admin")]
public void AddCustomer(CustomerDto customer)

 


If the current user isn’t authenticated or the authenticated user don’t belong to the role “Admin”,  the AuthorizeChangeSet will fail and an exception is thrown.


ValidateChangeSet

The next method that will be executed if the authorize validation passed during the Submit is the ValdiateChangeSet. This method will perform the server-side validation when the validation annotation is used on entities. If the validation fails on a entity in the ChangeSet the OnError method will be called and the Submit method will break. The following is an example about how to use the validation annotation on a Entity Framework or Linq to SQL generated class:

[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]
public partial class Customer
{
    internal sealed class CustomerMetadata
    {
         private CustomerMetadata()
         {
         }

         [Required]
         [RegularExpression("[A-Z][A-Za-z0-9]*")]
         [StringLength(32)]
         public string CompanyName;

         ...
        }
    }
}

If you use a DTO/”Presentation Model” no meta data types are needed, instead you can just add the validation attributes to the property of your DTO/”Presentation Model”:

public class Customer
{
      [Required]
      [RegularExpression("[A-Z][A-Za-z0-9]*")]
      [StringLength(32)]
      public string CompanyName { get; set;}

         ...
}

 

Note: The validation will take place on the client-side, so the WCF RIA Services validation annotation will do both a client-side validation and server-side. It’s the ValidateChangeSet method that will do the validation on the server-side.

ExecuteChangeSet

The ExecuteChangeSet will take place after the validation is passed. This method will make two internal execution, it will first iterate through the ChangeSet and execute the CUD (Create, Update and Delete) Operations, and then the “custom” methods will be executed if there are any in the ChangeSet. If the ChangeSet has the following ChangeSetEntries:

Operation = Insert, Entity = newCustomer

Operation = Update, Entity = updateCustomer

Operation = Delete, Entity = removeCustomer

and the following operation methods in the DomainService:

public void InsertCustomer(Customer customer)
        
public void UpdateCustomer(Customer customer)
       
public void DeleteCustomer(Customer customer)

 

The first method to be executed during the ExecuteChangeSet will be the InsertCustomer then the UpdateCustomer and last the DeleteCustomer. When the ExecuteChangeSet method is completed the PersitChangeSet method will be executed.


PersistChangeSet

The PersistChangeSet method will make sure to save the inserted, updated and deleted entities to a data source. If the LintToEntityDomainService is used the PersistChangeSet will make a call to the ObjectContext’s SaveChanges method, if LinqToSqlDomainService is used the PersistChangeSet will call the DataContext’s SubmitChanges method. If a normal DomainService is used (when you use DTO/”Presentation Model”), the PresistChangeSet will do nothing if you don’t implement it. If you for example uses nHibernate you can call the nHibernate’s Session’s Save method in the PersistChangeSet, if the other operation methods just add entities to or remove entities from the nHibernate’s session. If you simply use the Repository pattern, Business Logic Components or Data Access components, you don’t need to use the PersistChangeSet, instead the operations method will work against the components instead (of course it’s up to you and based on the way you want to persist the model).

The last method that will be executed by the Submit method is the ResolveChangeSet, it will only be executed if the ChangeSet’s Entities got any conflicts during the process of the Submit method.

ResolveChangeSet

The ResolveChangeSet will try to resolve any conflicts appeared during the execution of the Submit method. If the conflicts are solved the method will return true otherwise false. If LinqToEntityDomainService or the LinqToSqlEntityDomainService is used, the ResolveChangeSet will make a call to the ObjectContext’s SaveChanges or the DataContext’s SubmitChanges after it succeeded to resolve the entities.

Now when you have got the basic understanding about what the Submit method in the DomainService does, it’s time to see where to begin and end a transaction.


Using Transactions within the DomainService

I have seen some examples where people starts an transaction within the Submit method. A transaction should be short lived and by starting a Transaction within the Submit method like this:

public override bool Submit(ChangeSet changeSet)
{
     using (var trans = new TransactionScope())
     {
        var result = base.Submit(changeSet);
trans.Complete();


return result; } }

 

can make sure the transaction will be up an running during the time the Submit method will call the AuthorizationChangeSet, ValidateChangeSet, ExecuteCHangeSet and the PersistChangeSet. It can take time for the methods to be executed and there is basically no reason to have a open transaction during the execution of some of the methods. The only methods that may need the Transaction is the ExecuteChangeSet or the PersistChangeSet and maybe the ResolveChangeSet method, but still it's based on how you have implemented your own DomainSerivce. If you use the LinqToEntityDomainService or the LinqToSqlDomainServices the SaveChanges and SubmitChanges uses an implicit transaction or enlist in any ambient transaction and does all the necessary work in that transaction. The LinqToEntityDomainService and the LinqToSqlDomainServices will try to Save- or SubmitChanges after it tries to resolve some of the conflict during the ResolveChangeSet method.

The reason why you may want to being the transaction within the Submit method is to make sure the ResolveChangeSet will be using the same transaction as the PersistChangeSet and also the other methods, it's depends on the Business Layer and Data Access Layer you are using. Another solution to avoid having an transaction open before the PersistChangeSet is called, is by starting a transaction within the PersistChangeSet and Commit or rollback the exception within the Submit method, then the ResolveChangeSet will also reuse the same transaction if you need to do that:

private TransactionScope _trans = null;

protected override bool PersistChangeSet(ChangeSet changeSet)
{
     if (_trans == null )
_trans = new TransactionScope();



return base.PersistChangeSet(changeSet); } public override bool Submit(ChangeSet changeSet) { bool submitResult = false; try { var submitResult = base.Submit(changeSet); if (trans != null) trans.Complete(); } catch { if (trans != null) { trans.Dispose(); trans = null; } } return submitResult; }

 

EDIT: In most case you don't need to reuse the same Transaction used within the PersistChangeSet and the ResolveChangeSet, it depends on the Business Logic layer and Data Access Layer you are using. If you use a Transaction for the PersistChangeSet it will do a rollback if there was any conflicts or Commit if there wasn't. In the case where the transaction will Commit there will be no conflicts so the ResolveChangeSet will not be called. If there was a conflict, the transaction will do a rollback and the ResolveChangeSet will then be executed. The ResolveChangeSet can then use its own Transaction when it try to resolve the conflicts and submit changes while using the LinqToSqlDomainService or LinqToEntiesDomainService.

If you are using DTO/”Presentation Model” and your operation methods are working directly against your Business layer from the DomainService, you can start the transaction within the ExecuteChangeSet method, but it will also depends on your DAL.


The ChangeSet object

The ChangeSet object is like a Unit of Work (things that should be done in a specific order). The ChangeSet will contains a list of Domain Operations that should take place and also the entity which is part of that operation, for example if you do the following operation on the client-side:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
如果你希望通过 WCF 接收 `uni.uploadFile` 的数据,而不仅仅是文件,你可以按照以下步骤进行操作: 1. 在 WCF 服务的契约中,定义一个操作合同,用于接收文件数据。可以使用 `byte[]` 类型的参数来接收数据。例如: ```csharp [ServiceContract] public interface IFileService { [OperationContract] void UploadFileData(byte[] fileData); } ``` 2. 在服务实现类中,实现该操作合同,并将 `byte[]` 类型的参数用于处理数据。例如: ```csharp public class FileService : IFileService { public void UploadFileData(byte[] fileData) { // 处理文件数据 // 可以进行自定义操作,如保存到数据库、解析数据等 } } ``` 3. 在服务的配置文件中,配置绑定和终结点。可以使用基于 HTTP 的绑定,如 `basicHttpBinding` 或 `webHttpBinding`。例如: ```xml <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IFileService" /> </basicHttpBinding> </bindings> <services> <service name="YourNamespace.FileService"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IFileService" contract="YourNamespace.IFileService" /> </service> </services> </system.serviceModel> ``` 4. 在客户端调用代码中,引用服务契约并创建代理对象。然后,可以使用代理对象调用 `UploadFileData` 方法并传递数据。例如: ```csharp using (var client = new FileServiceClient()) { byte[] fileData = Encoding.UTF8.GetBytes("Your file data"); client.UploadFileData(fileData); } ``` 这样,你就可以在 WCF 中成功接收 `uni.uploadFile` 的数据。记得根据实际需求进行适当的异常处理和数据操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值