ADO.NET Data Services support

Posts   
1  /  2  /  3
 
    
Posts: 134
Joined: 10-Jan-2007
# Posted on: 11-Dec-2008 23:57:00   

I have created some templates for supporting ADO.NET Data Services, here are the contents of the readme in the attachment. Good luck!

Brian Chance

Purpose

Add support for ADO.NET Data Services to LinqMetaData Features: --Adds IgnoreProperties attribute for each entity for ADO.NET un-supported types (Validator, AuthorizerToUse, etc.) and extraneous LLBLGen Properties (i.e. LLBLGenProEntityName, IsDeserializing, etc.) --Adds DataServiceKey attribute for each entity to indicate primary keys --Implements IUpdatable on LinqMetaData to allow inserts and updates --Implements IExpandProvider on LinqMetaData to support the expand keyword (prefetch)

Installation

NOTICE!!!: I have updated the default LinqMetaData templates to make the LinqMetaData class partial Unpack archive to the LLBLGen Pro installation folder. You will be asked to overwrite Tasks and Templates.

Usage

The presets in the archive are meant to add one file LinqMetaData.adods.cs to an EXISTING c# project. To generate every time, merge the preset with the default SelfServicing or Adapter you are using.

Targets C# and .NET 3.5 only Open your LLBLGen project, F7 to gen Template group - SelfServicing or Adapter task queue to execute tab - Selected preset - AdditionalTemplates.SelfServicing/Adapter.LinqADODS Start Generator

This will add a new file to the Linq folder LinqMetaData.adods.cs Open your project and add references to System.Data.Services and System.Data.Services.Client In a web site, add a new item "ADO.NET Data Service", Add necessary references to use the LinqMetaData class

The service should look something like this:

using System; using System.Collections.Generic; using System.Data.Services; using System.Linq; using System.ServiceModel.Web; using System.Web; using System.Linq.Expressions; using LLBLEntities2.Linq; using LLBLEntities2.EntityClasses; using LLBLEntities2.DatabaseSpecific; using SD.LLBLGen.Pro.ORMSupportClasses;

namespace WebService1 { [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)] public class DataService1 : DataService<LinqMetaData> { public static void InitializeService(IDataServiceConfiguration config) { config.SetEntitySetAccessRule("*", EntitySetRights.All); config.UseVerboseErrors = true; EntityBase2.MarkSavedEntitiesAsFetched = true; }

    protected override LinqMetaData CreateDataSource()
    {
        return new LinqMetaData(new DataAccessAdapter());
    }
}

}

ADAPTER NOTES: --You need to override the CreateDataSource() to create the DataAccessAdapter --Set EntityBase2.MarkSavedEntitiesAsFetched = true because ADO.NET DS reads the object right after saving to serialize back

SELFSERVICING NOTES: --You only need to override CreateDataSource if you want to initialize a transaction

Implementation Notes

Expand keyword can specify multiple levels of prefetch - so var x = from o in LinqMetaData.OrderEntity.Expand("Products/Category,Products/Category/SubCategories") select o would retrieve Products, Products.Category and Products.Category.SubCategories using WithPath I ended up generating infrastructure code to handle the expansions to get the runtime typing correct.

ADO.NET attaches any QueryInterceptors on the DataService to the expand segments passed to the IExpandProvider.ApplyExtensions method. These are added as filters on the PathEdge. Make sure the QueryInterceptor entitySetName and T in the Func<T, bool> are the same type.

When objects are inserted, ADO.NET DS automatically re-reads the object from the database using the key and the IQueryable interface When objects are updated, ADO.NET DS automatically reads the object from the database then sets the values from the client.

Attachments
Filename File size Added on Approval
LinqADODSTemplates.zip 12,788 12-Dec-2008 17:10.55 Approved
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 12-Dec-2008 09:44:34   

You forgot the attachment wink

(for the rest: thanks a lot for your efforts!! smile )

Frans Bouma | Lead developer LLBLGen Pro
Posts: 134
Joined: 10-Jan-2007
# Posted on: 12-Dec-2008 17:12:07   

That might help. confused

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 12-Dec-2008 18:40:24   

great stuff!

I'll have a look soon (hopefully this weekend, otherwise monday)

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 16-Dec-2008 10:00:04   

We're looking into the code now, looks OK, I have some questions, but I'll get back to you on that. One remark: the release of v2.0 learned us that you can't generate a lot of code into 1 method (the persistence info init routine was originally 1 method), as that would cause invalid IL misery in larger projects (300+ entities or so). So the generated method with the switch/case for every entity isn't going to work in larger projects I think (as that method would then become really big.) I think it can be done with reflection but we've to check that. Stay tuned simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Posts: 134
Joined: 10-Jan-2007
# Posted on: 16-Dec-2008 16:41:36   

I would love to see reflection used. Some of the generic stuff was out of my ability to divine (aka google + reflector) an answer. I ended up on generation because I could not figure out how to:

a) get the IQueryable passed in ApplyExtensions to be the correct IQueryable<T> so I could call .WithPath<T>. I could not get back to the underlying type of the IQueryable base using runtime information that the compiler liked.

b) call new PathEdge<T> using the type with the child element type. One of the issues is the Filters are coming in as Expression<Func<T, bool>> where T : IEntityCore and that needed cast back to be passed into PathEdge<T> constructor.

c) another issue is how MS passes the ExpandSegments. They do not get rid of duplicates at each level, so Orders/Products,Orders/Shipping actually passes in 2 collections of segments. So the initial pass through is creates a tree of distinct paths, then builds the IPathEdge[] from the leaves back to the root.

Maybe some internal overloads to the methods would be easier or possibly injecting code into the entities themselves. I was not sure about modifying the core templates. What is the best method for adding to the core entity generation and giving back to the community?

Brian

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 17-Dec-2008 10:24:16   

brianchance wrote:

I would love to see reflection used. Some of the generic stuff was out of my ability to divine (aka google + reflector) an answer. I ended up on generation because I could not figure out how to:

a) get the IQueryable passed in ApplyExtensions to be the correct IQueryable<T> so I could call .WithPath<T>. I could not get back to the underlying type of the IQueryable base using runtime information that the compiler liked.

I'll toy with it a bit, Type.MakeGenericType is a good candidate to solve this simple_smile

b) call new PathEdge<T> using the type with the child element type. One of the issues is the Filters are coming in as Expression<Func<T, bool>> where T : IEntityCore and that needed cast back to be passed into PathEdge<T> constructor.

It might be better to use the WithPath(PrefetchPath(2)) overload, but I'm not sure.

c) another issue is how MS passes the ExpandSegments. They do not get rid of duplicates at each level, so Orders/Products,Orders/Shipping actually passes in 2 collections of segments. So the initial pass through is creates a tree of distinct paths, then builds the IPathEdge[] from the leaves back to the root.

Ah, I see simple_smile

Maybe some internal overloads to the methods would be easier or possibly injecting code into the entities themselves. I was not sure about modifying the core templates. What is the best method for adding to the core entity generation and giving back to the community? Brian

I think how you did it, through partial classes, is the best way. That way users can keep using our templates and use your templates as an add-on. I'll get back to you with feedback and other things soon. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Posts: 134
Joined: 10-Jan-2007
# Posted on: 17-Dec-2008 18:11:00   

Alright, I fixed the templates to use reflection instead of emitting code. My initial foray into reflection left me wanting because I was trying to solve the problem in one method. After realizing MS passed in multiple segments, the resulting code with methods worked. This code turned out to be pretty easy to use reflection with the MakeGenericMethod.

The only code gen now is for the attributes on the entity classes. Attached are newest templates. Not sure how to attach to the top thread?

Brian Chance

Attachments
Filename File size Added on Approval
LinqADODSTemplates.zip 12,719 17-Dec-2008 18:11.18 Approved
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 17-Dec-2008 18:32:35   

Thanks Brian, we'll look into these new batch and we'll get back to you what we'll do with it, as we'd like to post them on the front page together with the dynamic data templates and other templates.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 18-Dec-2008 10:26:50   

Couple of points: - the ignore attribute gives CLS compliant errors, which isn't your fault, it's just ironic that MS' own attributes give this problem... simple_smile - you have reflection usage in ApplyExpansions, to call a generic method. However, along the call chain, you don't really need 'T' as a generic type, but as a type instance, except for the WithPath call. The main disadvantage of the method reflection is that it's not allowed in medium trust scenario's. I'll see if I can change this code a bit, as it looks like a similar scenario to what's already in the linq provider. (edit) I see you need it in PathEdgeNode. Though all what's needed is a IPrefetchPathCore instance, as WithPath has an overload which accepts that. So pathEdge's aren't really necessary.

(edit) using the URL:

http://localhost:1777/WebSite1/WebDataService.svc/Customer('CHOPS')/Orders

I got a nullref crash in the Linq provider... no idea why/what query was executed, will have to check with tracing..

(edit) query: value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[ NW26.Adapter.EntityClasses.CustomerEntity]).Where(element => (element.CustomerId = "CHOPS")).SelectMany(element => Convert(element.Orders))

so it's likely the 'Convert' which has no meaning there. (always lovely how these Convert calls pop up at random occasions... )

(edit) The SelectMany makes no sense, it should have been Select(), not SelectMany()... confused Very odd query. SelectMany is a join (cross join) and typically occurs in queries like: var q = from c in metaData.Customer where c.CustomerId=="CHOPS" from o in c.Orders select o;

here, the two from's cause the selectmany to be emitted. This gives almost the traced expression tree, except SelectMany has two parameters, not 1.

However, when I try to reproduce the query using normal C#: var q = from c in metaData.Customer where c.CustomerId=="CHOPS" select c.Orders;

I get a Select call obviously, not a SelectMany.... (however the traced query is the same) The problem is that there's 1 argument missing for a normal SelectMany (just a source and a projection, which is a Select()), so the linq provider should perhaps convert it to Select() instead... looking into it.

Edit: this query reproduces it: LinqMetaData metaData = new LinqMetaData(adapter); var q = metaData.Customer.Where(c=>c.CustomerId=="CHOPS").SelectMany(c=>c.Orders); Indeed, SelectMany() has an overload which accepts a projection.... I missed this. It is different to Select(), in that it returns an IQueryable<OrderEntity> while Select here returns an IQueryable<EntityCollection<OrderEntity>>.... disappointed

(edit) creating the projectionselector should do the trick. I hope to have this done today.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 18-Dec-2008 16:40:21   

Fixed it simple_smile (the linq provider).

Will look into the linqmetadata stuff now.

(edit) cheered too soon, still an alias error due to the convert... cry

(edit) OK now it's fixed. simple_smile I've attached the new linq provider build which contains the fix. Not sure if you ran into this issue already. I'm planning to email Pablo Castro about Astoria operator -> linq operator guidelines, to see if I can dig up more things which might not be implemented properly in the linq provider.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 134
Joined: 10-Jan-2007
# Posted on: 18-Dec-2008 16:52:53   
  • you have reflection usage in ApplyExpansions, to call a generic method. However, along the call chain, you don't really need 'T' as a generic type, but as a type instance, except for the WithPath call. The main disadvantage of the method reflection is that it's not allowed in medium trust scenario's. I'll see if I can change this code a bit, as it looks like a similar scenario to what's already in the linq provider.

Could not figure out how to cast the IQueryably passed in to an IQueryable<T> instance to pass to WithPath.

(edit) I see you need it in PathEdgeNode. Though all what's needed is a IPrefetchPathCore instance, as WithPath has an overload which accepts that. So pathEdge's aren't really necessary.

For the PathEdgeNode, the QueryInterceptor filters are coming in as Expression<Func<T,bool>>, not sure how to make that an IPredicateExpression.

You are right though, if you could use IPrefetchPathCore you should not need the internal PathEdgeNode for storage and could just add the first time through. The way MS passes the expands(Orders/Products,Orders/Shipping comes in as 2 seperate collections), need to make sure they are not added twice.

http://localhost:1777/WebSite1/WebDataService.svc/Customer('CHOPS')/Orders

I never even tried this type of query, had I done so I probably would have thrown in the towel without deep knowledge of LINQ internals cry . Which probably only you and 3 guys at MS actually know smile .

Appreciate all the effort you have put into this. The documentation by MS is basically nothing on any of this stuff, the ADO.DS basically was built for Entity Framework and it shows.

Brian

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 18-Dec-2008 17:37:21   

brianchance wrote:

  • you have reflection usage in ApplyExpansions, to call a generic method. However, along the call chain, you don't really need 'T' as a generic type, but as a type instance, except for the WithPath call. The main disadvantage of the method reflection is that it's not allowed in medium trust scenario's. I'll see if I can change this code a bit, as it looks like a similar scenario to what's already in the linq provider.

Could not figure out how to cast the IQueryably passed in to an IQueryable<T> instance to pass to WithPath.

Hmm, that's indeed a problem... I do recall that I needed the same thing inside the linq provider, I'll see if I can dig up an equivalent piece of code.

(edit) I see you need it in PathEdgeNode. Though all what's needed is a IPrefetchPathCore instance, as WithPath has an overload which accepts that. So pathEdge's aren't really necessary.

For the PathEdgeNode, the QueryInterceptor filters are coming in as Expression<Func<T,bool>>, not sure how to make that an IPredicateExpression.

You are right though, if you could use IPrefetchPathCore you should not need the internal PathEdgeNode for storage and could just add the first time through. The way MS passes the expands(Orders/Products,Orders/Shipping comes in as 2 seperate collections), need to make sure they are not added twice.

Thanks, I'll look into this. Can't be TOO hard. I did write a similar routine for dynamic data, back in the early stages. I didn't add the stuff to sourcecontrol back then and later on ripped it out again, so I don't have the routine anymore, but it should be fairly straight forward.

http://localhost:1777/WebSite1/WebDataService.svc/Customer('CHOPS')/Orders

I never even tried this type of query, had I done so I probably would have thrown in the towel without deep knowledge of LINQ internals cry . Which probably only you and 3 guys at MS actually know smile .

heh simple_smile Well, it works now (see attachment previous post). I mailed Pablo to see if they have a conversion table somewhere so I can check whether all necessary linq operators are implemented.

Appreciate all the effort you have put into this. The documentation by MS is basically nothing on any of this stuff, the ADO.DS basically was built for Entity Framework and it shows. Brian

Actually, I think the design of the entity framework is partly driven by ADO.DS. If you look at the .Include(string) extension method for EF, to do a prefetch path kind of thing, that is seriously flawed with the string requirement etc. however for astoria this is OK, you can pass on the string you get from the URL. I always have had the feeling that Include method was added just for astoria. But indeed, some IUpdatable things are really odd.

Anyway, I'll dig some deeper with the code you made. At least your code works properly simple_smile .

(edit) I already found a gem in the Linq provider code: PathElementCreator which is used by the WithPath() overload which uses lambdas simple_smile . Accepts two types and a property name (e.g. 'Orders'). Jeremy Skinner (Jez on this forum) wrote this code, and it seems like the perfect candidate for creating prefetch paths without a lot of problems.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 18-Dec-2008 19:07:27   

Hmm. It's indeed impossible to get the right type at COMPILE time... it's not a problem to get to IQueryable<T>, but it's required to compile the WithPath() call.

WithPath simply adds a call to WithPath(edges) to the IQueryable<T> which is then handled further in the linq provider, so it's not something which is appendable easily. It could be done by using reflection on WithPath(), and then a small ExpressionTree should be created, but that's simply not going to make things better, it's simply transfering the reflection from one routine to the next simple_smile .

What's also sad is that ExpandSegment DOES have the type of the container in itself, ... it's internal however... They'll never learn, I guess.

Anyway, I'll clean up the stuff a bit and release the templates as-is tomorrow. First to the 3rd party section in the customer area. We'll contact you by email as well as you have spend some time on this which is a great add-on for our application. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Posts: 134
Joined: 10-Jan-2007
# Posted on: 18-Dec-2008 20:36:03   

Awesome, thanks for the quick work on digging out the issues. Way above expectations.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 19-Dec-2008 11:25:43   

I've cleaned up the code a bit, added xml comments (as some people use fxcop to force these comments everywhere and will get errors otherwise). I also made a change to the normal templates to make LinqMetaData classes partial, so the templates now only contain the additional templates simple_smile

I credited 'Brian Chance', without a company. If you want a company name or URL in the readme, let me know.

I'll attach the archive for clarity here, the required linq build is available in a previous post in the thread, and for people who can't wait till later today when the new build is released: make LinqMetaData partial. wink

I've sent you an email to the email address you used to register on this forum.

Attachments
Filename File size Added on Approval
AdditionalTemplates_ADONET_DataServices_12192008.zip 12,595 19-Dec-2008 11:25.56 Approved
Frans Bouma | Lead developer LLBLGen Pro
Posts: 134
Joined: 10-Jan-2007
# Posted on: 19-Dec-2008 16:21:35   

Thanks for all your help Frans. I hope to start working on a better client side library for silverlight/.net35. The generator produces some very un useful code (no property changed events = no binding support) and the DataServiceContext is truly odd (It is basically a UnitOfWork that you have to tell what changed).

Brian

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 19-Dec-2008 20:37:07   

brianchance wrote:

Thanks for all your help Frans. I hope to start working on a better client side library for silverlight/.net35. The generator produces some very un useful code (no property changed events = no binding support) and the DataServiceContext is truly odd (It is basically a UnitOfWork that you have to tell what changed). Brian

Hmm. simple_smile Sounds like a real afterthought, this framework of MS, which wouldn't be the first.

One thing I found a struggle, was how to test this ado.net dataservices stuff?

Anyway, I've posted your templates to the customer area -> 3rd party section. I marked it 'beta' as I'm not sure if there are small things which need to be ironed out. Thanks again for your time and effort in this! simple_smile

Frans Bouma | Lead developer LLBLGen Pro
vassos
User
Posts: 32
Joined: 24-Jun-2008
# Posted on: 22-Dec-2008 16:23:17   

Hi, Otis. I've just taken a short view over this thread, hoping to find an answer to my question. My question is do you have support for ADO.NET Data Services in LLBLGen. We use LLBLGen as an ORM product for our project. It works good enough. Now we started a MVC project that is about to consume data using ADO.NET DS. I know how to do that with ADO.NET Entity Framework and the .edmx file. My question is whether the .lgp data model file can be exposed to an ADO.NET DS. If yes please give me a tutorial how to do that.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 22-Dec-2008 17:36:35   

vassos wrote:

Hi, Otis. I've just taken a short view over this thread, hoping to find an answer to my question. My question is do you have support for ADO.NET Data Services in LLBLGen. We use LLBLGen as an ORM product for our project. It works good enough. Now we started a MVC project that is about to consume data using ADO.NET DS. I know how to do that with ADO.NET Entity Framework and the .edmx file. My question is whether the .lgp data model file can be exposed to an ADO.NET DS. If yes please give me a tutorial how to do that.

Please see: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=14968

The readme explains what to do, it's very straight forward. Be sure you are using the latest v2.6 build.

Frans Bouma | Lead developer LLBLGen Pro
tolo
User
Posts: 15
Joined: 27-Mar-2005
# Posted on: 25-Jan-2009 17:54:28   

Hi,

I'm trying to publish an existing LLBLGen project using this template. I had to fix several problems with inheritance but I can read and write the entities. Unfortunately I don't know how I can force the concurrency control. The concurrency check happens but the old value and the new value of the concurrency field are the same. I tried to decorate my entities with the ETag attribute but when I save the entities I get an exception: "Since entity type 'NovaEngel.EntityClasses.RegionEntity' has one or more etag properties, If-Match HTTP header must be specified for PUT operations on this type."

Do you know how to fix this?

Thanks for the template.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 26-Jan-2009 12:09:09   

Looking at the documentation of the ETagAttribute, it seems that it doesn't support If-[None-]Match requests (over HTTP). So if you want to have this attribute being supported, the request made to the service must have an if-match element in the HTTP header of the request.

The big question now is of course: how to do that? I have no idea. flushed

Frans Bouma | Lead developer LLBLGen Pro
tolo
User
Posts: 15
Joined: 27-Mar-2005
# Posted on: 27-Jan-2009 15:37:14   

Otis wrote:

Looking at the documentation of the ETagAttribute, it seems that it doesn't support If-[None-]Match requests (over HTTP). So if you want to have this attribute being supported, the request made to the service must have an if-match element in the HTTP header of the request.

The big question now is of course: how to do that? I have no idea. flushed

I have found the problem, it was my fault flushed

I was using one LinqMetaData for the query and another one for the update. I linked the entity read by the first LinqMetaData to the second one using AttachTo, but I forgot to specify the etag confused

I will try to modify the templates to handle the inheritance problems, it doesn't look difficult.

Thanks again.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 27-Jan-2009 15:43:32   

Glad it's solved simple_smile

If you have more information to report about the inheritance problems + fixes, please post back in this thread so others can benefit too. Thanks in advance. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
tomahawk
User
Posts: 169
Joined: 02-Mar-2005
# Posted on: 05-Mar-2009 23:41:44   

I would be very interested to know what the inheritance fixes are, as I am attempting to build an ADO Data Service web portal. I get the following response from the service:


The server encountered an error processing the request. The exception message is 'Property 'Contact' and 'Business' are IQueryable of types 'CL.DAL.EntityClasses.ContactEntity' and 'CL.DAL.EntityClasses.BusinessEntity' and type 'CL.DAL.EntityClasses.ContactEntity' is an ancestor for type 'CL.DAL.EntityClasses.BusinessEntity'. Please make sure that there is only one IQueryable property for each type hierarchy.'. See server logs for more details. The exception stack trace is:

at System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadata(IDictionary`2 knownTypes, IDictionary`2 entitySets) at System.Data.Services.Providers.BaseServiceProvider.PopulateMetadata() at System.Data.Services.DataService`1.CreateProvider(Type dataServiceType, Object dataSourceInstance, DataServiceConfiguration& configuration) at System.Data.Services.DataService`1.EnsureProviderAndConfigForRequest() at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody) at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] ) at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

1  /  2  /  3