RunLocal vs. custom data portal proxy

RunLocal vs. custom data portal proxy

Old forum URL: forums.lhotka.net/forums/t/5182.aspx


Michael Hildner posted on Thursday, July 31, 2008

Greetings,

I'm running into the situation where some objects need to use remoting, and others need to run locally. Reading the threads on this, it seems it can be done either with the RunLocal attribute or creating your own custom data portal proxy.

Is there much of a difference between the two approaches? I'm trying to decide the best route to take.

Thanks,

Mike

ajj3085 replied on Thursday, July 31, 2008

Well I'd say go with the RunLocal attribute.  It's easy, and that's all you have to do it remember to add it in.  The custom proxy is going to require you to build some code, which may not be difficult, but is almost re-inventing the wheel.  Also, it's more for your to maintain and test.

Michael Hildner replied on Thursday, July 31, 2008

Thanks for the reply. That's what I was leaning towards too, like you said, it's easy. Just wasn't sure if I was missing something with the custom proxy. I guess my needs just don't warrant that.

tmg4340 replied on Thursday, July 31, 2008

If you have control over all your object's code, using the "RunLocal" attribute is the technically easier option, since you're leveraging already-written-and-supported code.  But depending on the number of objects that have to run locally, it may be more code to deal with - after all, you have to add that attribute to every DP_ method in every class that runs locally.

The custom DataPortal proxy is a more centralized solution, and can make your BO's cleaner, as you don't have to sprinkle attributes all over.  But it also adds to your code base, and to your configuration overhead.  Since all you want to do is route to a pre-defined proxy, your custom proxy code is pretty simple.  If you write the custom proxy, you have to maintain it as you migrate through versions of CSLA.  But like I said, the code is fairly simple, and I don't see Rocky changing the DataPortal design to a point where the code you have to write goes up substantially.

So the difference is really between writing code and not writing code.  I don't know if we can give a "best route" recommendation.  To me, it's a kind of apples-and-oranges comparison.  I'd look more at your comfort level for writing and maintaining "infrastructure code" - even relatively simple stuff like this - versus using what the framework already gives you.

HTH

- Scott

Michael Hildner replied on Thursday, July 31, 2008

Thanks Scott, that's some good info there. Always trade-offs. At least we have options, which is great. And I do have control over all of the objects.

Allow me a follow up question. Should we decide to go the custom proxy route, the proxy would have to determine somehow whether to use remoting or go local. I know I need to re-read chapter 4 before getting into that. But how do people actually implement that? Wouldn't we need an attribute on the methods (or something similar) so the proxy would know which one to use?

I guess I'm a little concerned that it would be easy to forget to put the RunLocal attribute on a method, although testing would find that pretty quickly.

tmg4340 replied on Thursday, July 31, 2008

Michael Hildner:

Thanks Scott, that's some good info there. Always trade-offs. At least we have options, which is great. And I do have control over all of the objects.

Allow me a follow up question. Should we decide to go the custom proxy route, the proxy would have to determine somehow whether to use remoting or go local. I know I need to re-read chapter 4 before getting into that. But how do people actually implement that? Wouldn't we need an attribute on the methods (or something similar) so the proxy would know which one to use?

I guess I'm a little concerned that it would be easy to forget to put the RunLocal attribute on a method, although testing would find that pretty quickly.

Well... I haven't seen anyone list a specific implementation, but I can think of a couple.  The concept is the same, with the choice of whether you want to decorate your objects with attributes or enter configuration information.  Note that I'm going off your original description about entire objects being local or remote, and not just individual DP_ methods.  If it's individual methods, you might as well use RunLocal().

First off, your custom proxy would be a local one - after all, there's no reason to go to the server just to find out you have to try and come back and launch the local process.  I'm not even sure how you'd do that...

In any event, one option would be to create a custom attribute that you decorate your BO's with.  The DP methods either receive an object type or the object itself, from which the type can be retrieved.  You then reflect across the type and see whether it's decorated with that attribute.  Whether you mark the local objects or the remote objects is up to you, but you then create a proxy of the correct type based on that attribute and delegate the call.  Since it's your own attribute, you can make it inheritable if you want, thus avoiding the need to put it on subclasses.  But you still should be able to override the inherited attribute on specific subclasses if you want.

Another option is to create a configuration file (or put configuration entries into your existing configuration file) and house the information there.  Again, you're storing by type, and you can either create a complete catalog of types, or only the types of one category.  Conceptually, the code for this solution is the same as the attribute-based one - it's just the source for the decision tree that's different.  Inherited behavior is a little trickier here, as you don't really have facilities for .NET to walk the inheritance tree for you.  But you can certainly walk the inheritance tree manually.

You also could create your delegated proxies in your proxy constructor and cache them, thus saving you the overhead of creating a proxy each time.  I believe CSLA caches the proxy object that it uses, and you really do only need one of each.

Obviously, choosing the configuration-based route means you have to distribute that information to the machines, whereas an attribute is baked into your code.  But the configuration file allows for changes without needing a re-deployment.

One thing to consider is that this scheme wouldn't work if you have objects that could run in either location.  However, managing something like that would be non-trivial, and perhaps not possible, within the context of a DataPortal proxy.  But I also can't think of a situation where you'd want to do that outside of using RunLocal() on specific DP methods.

HTH

- Scott

Michael Hildner replied on Thursday, July 31, 2008

tmg4340:

One thing to consider is that this scheme wouldn't work if you have objects that could run in either location.  However, managing something like that would be non-trivial, and perhaps not possible, within the context of a DataPortal proxy.  But I also can't think of a situation where you'd want to do that outside of using RunLocal() on specific DP methods.

Scott, are you saying that the configuration-based route wouldn't work if you have objects that could run in either location?

One thing we may need to support, and this would be decided per installation,  is our libraries need to run either locally or remotely.

I can see where the RunLocal is baked into the code, so we'd need two copies of our libraries. This is why I'm looking into creating a custom proxy.

I really appreciate your information. I'm sure I'll be reading that post a few times as I try to create a custom proxy :)

ajj3085 replied on Thursday, July 31, 2008

Hmm... I know this was discussed before, but I can't remember how it worked.  I wonder if it would be possible to put the attribute on a base class override of all the DP_ methods.  Will the DP look "up" the inheritance chain if it doesn't find an attribute on the direct sub class?  Something else to look into.

Michael Hildner replied on Thursday, July 31, 2008

I couldn't find any discussion on the actual implementation, so if anyone knows, or could provide a link, that would be appreciated.

ajj3085 replied on Thursday, July 31, 2008

Fortunately, this was bugging me, and I have some down time.  Here's the thread I was refering to:

http://forums.lhotka.net/forums/thread/5530.aspx

So, if you're using 2.1 or higher, it looks like my subclass idea won't work without modifying Csla, which presents its own risks.  It's kind of a shame though.. inheriting the attribute would allow the behavior you want (usually runlocal) if accompanied by a RunRemote attribute.  Which you could probably add into Csla... but I hesitate to modify Csla too much myself.

Jason Berkan replied on Thursday, July 31, 2008

Michael,

You don't say what version of the CSLA you are using, but I just went through this with v2 and it is not possible to use a custom proxy, as the proxy does not know what object it is being run on in the IsServerRemote method, so you cannot return the correct information.  You must modify the CSLA code or use the RunLocal attribute.  I don't know anything about other versions of the CSLA unfortunately.

For the modifications, I created a RunRemote attribute (copy of RunLocal renamed).  I then changed GetDataPortalProxy in DataPortal\Client\DataPortal.vb as follows:

Private mLocalPortal As DataPortalClient.IDataPortalProxy

Private mRemotePortal As DataPortalClient.IDataPortalProxy

Private mPortal As DataPortalClient.IDataPortalProxy

Private Function GetDataPortalProxy( _

ByVal forceLocal As Boolean, ByVal forceRemote As Boolean) As DataPortalClient.IDataPortalProxy

If forceLocal Then

If mLocalPortal Is Nothing Then

mLocalPortal = New DataPortalClient.LocalProxy

End If

Return mLocalPortal

End If

If forceRemote Then

If mRemotePortal Is Nothing Then

mRemotePortal = New DataPortalClient.RemotingProxy

End If

Return mRemotePortal

End If

If mPortal Is Nothing Then

Dim proxyTypeName As String = ApplicationContext.DataPortalProxy

If proxyTypeName = "Local" Then

mPortal = New DataPortalClient.LocalProxy

Else

Dim typeName As String = _

proxyTypeName.Substring(0, proxyTypeName.IndexOf(",")).Trim

Dim assemblyName As String = _

proxyTypeName.Substring(proxyTypeName.IndexOf(",") + 1).Trim

mPortal = DirectCast(Activator.CreateInstance(assemblyName, _

typeName).Unwrap, DataPortalClient.IDataPortalProxy)

End If

End If

Return mPortal

End Function

I then added a RunRemote method:

Private Function RunRemote(ByVal method As MethodInfo) As Boolean

Return Attribute.IsDefined(method, GetType(RunRemoteAttribute), False)

End Function

The final code change was to update calls to GetDataPortalProxy:

proxy = GetDataPortalProxy(RunLocal(method), RunRemote(method))

Finally, just add the CslaDataPortalUrl entry in your app.config/web.config.  Do not put in the CslaDataPortalProxy line.

Jason

Michael Hildner replied on Thursday, July 31, 2008

Jason Berkan:

You don't say what version of the CSLA you are using, but I just went through this with v2 and it is not possible to use a custom proxy, as the proxy does not know what object it is being run on in the IsServerRemote method, so you cannot return the correct information.  You must modify the CSLA code or use the RunLocal attribute.  I don't know anything about other versions of the CSLA unfortunately.

This project is on 2.1.4. I wonder what's the minimum version to be able to use a custom proxy? It's starting to look like we'll have to do this, although it's not an immediate need.

Thanks for posting your code - I may need it.

tmg4340 replied on Thursday, July 31, 2008

Jason Berkan:

You don't say what version of the CSLA you are using, but I just went through this with v2 and it is not possible to use a custom proxy, as the proxy does not know what object it is being run on in the IsServerRemote method, so you cannot return the correct information.  You must modify the CSLA code or use the RunLocal attribute.  I don't know anything about other versions of the CSLA unfortunately.

I would have to test it out, but there actually might be a way to make this work.

"IsServerRemote" is used by the DataPortal's Create, Fetch, Update, and Delete methods.  But it's only used once before the proxy methods are called, and that's to create the DataPortalContext.  That context is then passed into your proxy routines, which would pass it along to your delegated proxy classes (which finally pass it to the server DataPortal).  There shouldn't be anything stopping you from discarding that DataPortalContext in the proxy routines, creating your own to pass to your delegated proxy object using the proper "IsServerRemote" value, and updating the "IsServerRemote" property so that the DataPortal code after your call has correct info to work with.  It's a slight duplication of the code in the client DataPortal object, but it shouldn't hurt anything, and it's not very labor-intensive code.

There are two monkey wrenches to this.  One, the "DataPortalInvoke" and "DataPortalInvokeComplete" events would not have the correct DataPortalContext objects to provide to event consumers.  Two, in version 3.0+, you would potentially lose the auto-cloning code in the Update method, or possibly invoke it when you don't want it.

I'm certainly not going to call this a "recommended practice".  But if you can live with the consequences of this technique, this should work.  That may be a big "if".

Michael Hildner:

Scott, are you saying that the configuration-based route wouldn't work if you have objects that could run in either location?

One thing we may need to support, and this would be decided per installation,  is our libraries need to run either locally or remotely.

I can see where the RunLocal is baked into the code, so we'd need two copies of our libraries. This is why I'm looking into creating a custom proxy.

I really appreciate your information. I'm sure I'll be reading that post a few times as I try to create a custom proxy :)

The configuration-based solution would work so long as you don't have to mix locations within the same installation.  If the location is the same throughout the application installation, but different installations have different requirements, then the configuration-based solution should work just fine - and it's the one I'd go with.

HTH

- Scott

Jason Berkan replied on Thursday, July 31, 2008

tmg4340:

"IsServerRemote" is used by the DataPortal's Create, Fetch, Update, and Delete methods.  But it's only used once before the proxy methods are called, and that's to create the DataPortalContext.  That context is then passed into your proxy routines, which would pass it along to your delegated proxy classes (which finally pass it to the server DataPortal).  There shouldn't be anything stopping you from discarding that DataPortalContext in the proxy routines, creating your own to pass to your delegated proxy object using the proper "IsServerRemote" value, and updating the "IsServerRemote" property so that the DataPortal code after your call has correct info to work with.  It's a slight duplication of the code in the client DataPortal object, but it shouldn't hurt anything, and it's not very labor-intensive code.

Where were you two days ago?  :)

This definitely does work, with the small concerns that you pointed out.  I currently do not have any code executing in the events, so it does not matter that the DataPortalContext is wrong.  The proxy I created is posted below - it's nothing earth shattering.  I had to copy in a couple of CSLA methods to make the code work, and I could not get my RunRemote attribute to work, but that may just be an assembly issue.  For testing, I hardcoded in the name of my library that should be run remotely.

Imports Csla

Public Class MyDataPortalProxy

Implements DataPortalClient.IDataPortalProxy

Private mLocalProxy As New DataPortalClient.LocalProxy

Private mRemotingProxy As New DataPortalClient.RemotingProxy

Public ReadOnly Property IsServerRemote() As Boolean Implements Csla.DataPortalClient.IDataPortalProxy.IsServerRemote

Get

' Default to running locally, and we will create a new DataPortalContext if we

' need to run the method remotely.

Return False

End Get

End Property

Public Function Create(ByVal objectType As System.Type, ByVal criteria As Object, ByVal context As Csla.Server.DataPortalContext) As Csla.Server.DataPortalResult Implements Csla.Server.IDataPortalServer.Create

If RunRemote(objectType) = True Then

Dim dpContext As New Server.DataPortalContext(GetPrincipal, True)

Return mRemotingProxy.Create(objectType, criteria, dpContext)

Else

Return mLocalProxy.Create(objectType, criteria, context)

End If

End Function

Public Function Delete(ByVal criteria As Object, ByVal context As Csla.Server.DataPortalContext) As Csla.Server.DataPortalResult Implements Csla.Server.IDataPortalServer.Delete

If RunRemote(GetObjectType(criteria)) = True Then

Dim dpContext As New Server.DataPortalContext(GetPrincipal, True)

Return mRemotingProxy.Delete(criteria, dpContext)

Else

Return mLocalProxy.Delete(criteria, context)

End If

End Function

Public Function Fetch(ByVal objectType As System.Type, ByVal criteria As Object, ByVal context As Csla.Server.DataPortalContext) As Csla.Server.DataPortalResult Implements Csla.Server.IDataPortalServer.Fetch

If RunRemote(objectType) = True Then

Dim dpContext As New Server.DataPortalContext(GetPrincipal, True)

Return mRemotingProxy.Fetch(objectType, criteria, dpContext)

Else

Return mLocalProxy.Fetch(objectType, criteria, context)

End If

End Function

Public Function Update(ByVal obj As Object, ByVal context As Csla.Server.DataPortalContext) As Csla.Server.DataPortalResult Implements Csla.Server.IDataPortalServer.Update

If RunRemote(obj.GetType) = True Then

Dim dpContext As New Server.DataPortalContext(GetPrincipal, True)

Return mRemotingProxy.Update(obj, dpContext)

Else

Return mLocalProxy.Update(obj, context)

End If

End Function

Private Function RunRemote(ByVal objectType As System.Type) As Boolean

Return objectType.FullName.StartsWith("RemotingLibrary")

'Return Attribute.IsDefined(objectType, GetType(RunRemoteAttribute), False)

End Function

Private Function GetObjectType(ByVal criteria As Object) As Type

If criteria.GetType.IsSubclassOf(GetType(CriteriaBase)) Then

' get the type of the actual business object

' from CriteriaBase

Return CType(criteria, CriteriaBase).ObjectType

Else

' get the type of the actua. l business object

' based on the nested class scheme in the book

Return criteria.GetType.DeclaringType

End If

End Function

Private Function GetPrincipal() As System.Security.Principal.IPrincipal

If ApplicationContext.AuthenticationType = "Windows" Then

' Windows integrated security

Return Nothing

Else

' we assume using the CSLA framework security

Return ApplicationContext.User

End If

End Function

End Class

Jason

tmg4340 replied on Thursday, July 31, 2008

Well... a couple of days ago, I was figuring that Rocky knew best about his framework.  Smile [:)]

I'm still not guaranteeing that this concept doesn't have any unforeseen hiccups.  Fortunately, the two issues I mentioned aren't a problem for you, but they very well could be for other folks.  And without modifying CSLA code, I don't see any way around them.

I didn't take a hard look at your code, but I did notice one thing that you really should change.  Your default value of "False" for IsServerRemote is fine, but if you do end up using the RemotingProxy, you should change that property value to "True".  There is code after the DP methods that relies on that property, and you want that to work like it's supposed to.  If you just add a backing field for IsServerRemote, you can easily take care of this.  That way, the context objects flow correctly when you do make a remote call.

- Scott

Jason Berkan replied on Friday, August 01, 2008

Good catch.  I was throwing the code together pretty fast yesterday, as I wanted to see if it would work or not, and my simple tests didn't rely on IsServerRemote being correct after the dataportal call.

Thanks for your help.

Jason

jeff replied on Thursday, July 31, 2008

Here's a very simple "switchable" data portal proxy that I'm using. Just drop it in your project and change your config file to reference SwitchableDataPortalProxy rather then RemotingProxy. If certain classes are always local vs remote then definitely use the attributes, but this class here will work for arbitrarily switching at runtime (I didn't read the whole thread but FWIW this might be useful):

    public class SwitchableDataPortalProxy : IDataPortalProxy
    {
        public static bool UseLocalDataPortal = false;

        public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
        {
            if (UseLocalDataPortal)
                return new LocalProxy().Fetch(objectType, criteria, context);
            else
                return new RemotingProxy().Fetch(objectType, criteria, context);
        }

        public DataPortalResult Create(Type objectType, object criteria, DataPortalContext context)
        {
            if (UseLocalDataPortal)
                return new LocalProxy().Create(objectType, criteria, context);
            else
                return new RemotingProxy().Create(objectType, criteria, context);
        }

        public DataPortalResult Update(object obj, DataPortalContext context)
        {
            if (UseLocalDataPortal)
                return new LocalProxy().Update(obj, context);
            else
                return new RemotingProxy().Update(obj, context);
        }

        public DataPortalResult Delete(object criteria, DataPortalContext context)
        {
            if (UseLocalDataPortal)
                return new LocalProxy().Delete(criteria, context);
            else
                return new RemotingProxy().Delete(criteria, context);
        }
    }

Michael Hildner replied on Thursday, July 31, 2008

Hey, thanks Jeff. I was just about to start writing one of these, so you saved me some time.

decius replied on Friday, November 12, 2010

.

decius replied on Friday, November 12, 2010

 

jeff
Here's a very simple "switchable" data portal proxy that I'm using. Just drop it in your project and change your config file to reference SwitchableDataPortalProxy rather then RemotingProxy. If certain classes are always local vs remote then definitely use the attributes, but this class here will work for arbitrarily switching at runtime (I didn't read the whole thread but FWIW this might be useful):

    public class SwitchableDataPortalProxy : IDataPortalProxy
    {
        public static bool UseLocalDataPortal = false;

        public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
        {
            if (UseLocalDataPortal)
                return new LocalProxy().Fetch(objectType, criteria, context);
            else
                return new RemotingProxy().Fetch(objectType, criteria, context);
        }

        public DataPortalResult Create(Type objectType, object criteria, DataPortalContext context)
        {
            if (UseLocalDataPortal)
                return new LocalProxy().Create(objectType, criteria, context);
            else
                return new RemotingProxy().Create(objectType, criteria, context);
        }

        public DataPortalResult Update(object obj, DataPortalContext context)
        {
            if (UseLocalDataPortal)
                return new LocalProxy().Update(obj, context);
            else
                return new RemotingProxy().Update(obj, context);
        }

        public DataPortalResult Delete(object criteria, DataPortalContext context)
        {
            if (UseLocalDataPortal)
                return new LocalProxy().Delete(criteria, context);
            else
                return new RemotingProxy().Delete(criteria, context);
        }
    }

 

I know this post is really old, but I've run into the same requirement: switching remote vs local at runtime.

It seems to me that the above code would cause threading issues with the UseLocalDataPortal field being static. Plus, Isn't the proxy cached for performance? How bad of a performance cost would ctoring a new proxy for each dataportal request cause? I suppose I could just ctor a member variable like the VB code above does for that...

Also, I see the caveats that tmg4340 notes. If the dataportalcontext thinks it's local, but the proxy then executes fetch remotely, what are the consequences to that?

From the looks of it, it seems that I will have to make sure to set the dataportalcontext isremote based on the objecttype when passed to IDataPortalProxy methods - otherwise, the application context wiill not get set once on the remote server, correct? But wait... that property is readonly on the dataportal context.... Also, it seems that any dataportalinvoke events might not have the correct isremote value... am I on the right track here to understanding this? Is there something I'm missing?

I thought about creating my own RunRemote attribute, but it would seem silly to duplicate the caching efforts of the DataPortalMethodInfo cache that csla does for me, and I don't want to mess with customizing the framework for sure...

Besides all that, is there a newer, better way than to just create a custom proxy like this?

btw, I'm using csla 3.8.3

decius replied on Friday, November 12, 2010

Well the more I analyze the csla framework source, the more dissappointed I'm getting. As to my feable knowledge, it appears there's simply not a way to do tell Csla to run remote for a single class without sacraficing the loss of the ApplicationContext once passed to the server. I would love to be proven wrong on that because the ApplicationContext is essential for me.

I'll keep pecking at this, but I'm two steps away from sprinkling RunLocal attributes throughout my project. And I have about 50 objects, so that really sucks. Bummer too, this was the main reason I chose Csla for this particular project (we didn't know if we'd need remote resources or not for a small handful of items).

RockfordLhotka replied on Friday, November 12, 2010

A custom proxy should solve your problem.

The only trick with a custom proxy like this, is that you need to determine what conditions trigger the use of local vs remote calls. That could be a custom attribute you define, a config lookup based on the type of business object, or anything else you can imagine.

Sure, the default data portal proxies are simple - they are designed to support direct n-tier models. But a custom proxy isn't that hard to build, and you can do anything you want in that proxy - the possibilities are nearly limitless.

So don't be discouraged, this isn't that hard of a problem to solve.

Again, the first and most important question you need to answer, is how will your custom proxy determine which object(s) should be remote vs local.

And a very easy way to do this is with a custom attribute you define that is attached to the business class itself - that's easy to find.

decius replied on Friday, November 12, 2010

Thanks Rocky, yes, that's precisely what I've built, a custom attribute - I'm just concerned about the dataportalcontext getting messed up like tmg4340 mentions, and in looking at the way the source flows, I do see what he's getting at... I'll admit I don't have a full grasp on some of the inner workings of the framework, but it appears that changing the IsServerRemote on the fly in IDataPortal's methods may cause breif inconsistancies in the DataportalContext's IsRemote property. Should I not worry about this?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Csla.DataPortalClient;
using Csla.Server;

namespace Apac.Library.CustomProxy
{
 public class SwitchableDataPortalProxy : IDataPortalProxy
 {
  private RemotingProxy _remote = new RemotingProxy();
  private LocalProxy _local = new LocalProxy();

  public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
  {
   if (!IsRemote(objectType)) return _local.Fetch(objectType, criteria, context);
   else return _remote.Fetch(objectType, criteria, context);
  }

  public DataPortalResult Create(Type objectType, object criteria, DataPortalContext context)
  {
   if (!IsRemote(objectType)) return _local.Create(objectType, criteria, context);
   else return _remote.Create(objectType, criteria, context);
  }

  public DataPortalResult Update(object obj, DataPortalContext context)
  {
   if (!IsRemote(obj.GetType())) return _local.Update(obj, context);
   else return _remote.Update(obj, context);
  }

  public DataPortalResult Delete(Type objectType, object criteria, DataPortalContext context)
  {
   if (!IsRemote(objectType)) return _local.Delete(objectType, criteria, context);
   else return _remote.Delete(objectType, criteria, context);
  }

  public bool IsRemote(Type objectType)
  {
   if (Env.ApacEnv == EnvSetting.Prod && Attribute.IsDefined(objectType, typeof(RunRemoteAttribute), false))
   {
    IsServerRemote = true;
    return true;
   }
   return false;
  }

  public bool IsServerRemote
  {
   get { return false; }
   protected set { IsServerRemote = value; }
  }

  /// <summary>
  /// Marks a DataPortal_XYZ method to
  /// be run on the server for the switchable proxy
  /// </summary>
  [AttributeUsage(AttributeTargets.Class)]
  public sealed class RunRemoteAttribute: Attribute
  {

  }
 }
}

 

ajj3085 replied on Friday, November 12, 2010

If you build your own proxy that looks at your attribute,  you should be able to simply call one of the other Csla proxies to do the work.  after all, the Simple proxy and the wcf do what you want... your proxy just needs to pick the right one at the right time.

Copyright (c) Marimer LLC