is it possible to change the DataPortalURL in code?

is it possible to change the DataPortalURL in code?

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


sune42 posted on Thursday, July 06, 2006

hi

is it possible to change the DataPortalURL in code?

As I want to the option to change the Server in my application loginform.

 

 

Ruckus77 replied on Thursday, July 06, 2006

Blib blah, boo ha. In the out to the dog, mouse is I.

RockfordLhotka replied on Friday, July 07, 2006

No, it is not possible to change the URL in code using the existing data portal channels.

However, the data portal is specifically designed to be extensible - and that means you have the ability to write your own channel that could (for instance) allow dynamic changes to the server URL.

Each of the four existing channels are discussed in Chapter 4, and you could use any of them as a base for building your own channel. You can also look at the prototype WcfChannel (http://www.lhotka.net/Articles.aspx?id=0eec56bb-2a61-47c4-a9ca-f98371db1cad) to see how an external channel assembly is created.

I think there are all sorts of interesting possibilities here. Not only could you create a channel that allowed dynamic URL changes, but you could create a channel that had different rules for local vs remote calls, which is another very common request (online/offline mode switching).

razorkai replied on Friday, July 14, 2006

Hi sune42

Have you got anywhere with this?  Our application needs the option of running against multiple dataportal servers, as we have different "Environments" available to a user e.g. Live, Training, Test.  Each environment has its own Server and Database, and the user needs to be able to select the environment on startup.  Has anyone else done anything like this?

TIA.

odie replied on Friday, July 14, 2006

I have not had to deal with changing the Server but do have to give the user the ablity to select different databases. Here is what I wrote on another post a while back:

We have a similar situation where we have 3 Regions each with their own seperate database due to distance between locations. Additionally we have a development copy of the database for our own testing.

It may not be eligant but it works.

I have the following in my app.config file because until I get the connection string I can't get to a server.
<add key="ConfigRegionCount" value="3" />
<
add key="ConfigRegion1" value="Calgary" />
<
add key="ConfigRegion2" value="Edmonton" />
<
add key="ConfigRegion3" value="Regina" />

On my login form the user selects the region they wish to log into. Additionally I have a check box option for development database, but I wont go into that here.

Then based on which region they select I know which encrypted connection string to get from the database which looks like this.

<add key="DB:Calgary" value="bbNSKIAS8yO7...=" />
<
add key="DB:Edmonton" value="j2X70krzexwuHFjNX...=" />
<
add key="DB:Regina" value="HFjNXLK5MeJ0GN3K.." />
<
add key="DB:Development" value="Qs7FXSVjM2k/uETt3cn5qnC6g..." />

This allows for any number of connection strings, if you have to add another you only have to add tow lines to your app.config file. Based on the region selected it knows what connection string to use. If the user wants to switch database they simply logoff which brings up the logon screen again and they select a different database. I store the users last logged on region to start with as the user is likely logging into the same database all the time. I don't have to worry about users logging into the wrong database as this is cared for by the security model we have implemented.

Additionally the connections string is encrypted multiple times embedding both the data database connection string as well as the security database connection string together. But that another story.

razorkai replied on Friday, July 14, 2006

Hi odie.

Thanks very much for the info.  Perhaps I'd better clarify.  When I said "Each environment has its own Server and Database" I meant that each environment has its own DataPortal Server that will always connect to the Database associated with that environment e.g. Test DataPortal Server will connect to database TestDB and Training DataPortal Serverwill always connect tp database TrainDB.  So the ability to switch DataPortalURL is the critical part for me.

 

Wbmstrmjb replied on Friday, July 14, 2006

I have a similar issue.  I need to allow data portal changes on the fly based on which account a user is viewing.  If some criteria of that record is true, then use one dp for access, otherwise use another. 

I can see how a channel can be written for your own needs, but I am having trouble seeing how you could make it dynamic on the fly based on the data.  Has anyone already done this or can give me a theoretical idea of how to do it?  I'd be happy to share my results.

Thanks,

Mike

xal replied on Friday, July 14, 2006

Well, one thing you could do is have the classes that need a different dataportal from the default implement some interface like.

Public Interface IDataportalHelper
    Function GetDataportalType() As String 'or whatever
    Function GetDataportalPath() As String
End Interface


And then your dataportal channel could check to see if the class implements that and take the appropiate route based on the information returned by those functions. Since the functions are implemented inside the actual classes, you could return different dataportal paths / types based on the object's data.

You would also need to do something similar for criteria objects, because usually you get or delete data based on the criteria alone. You could just implement the same interface in the criteria.

I will at some point have to do something similar, but in my case, it's simpler. What I need is to use a simpledataportal most of the time and use a remoting (or other, which I haven't yet decided) dataportal for a few objects that need to run some things on the server like reading some files that are not accesible through network shares. So for this case I'm thinking of just setting a class level attribute that indicates the object needs to pass through the remote dataportal and that's it.

My $0.02

Andrés

razorkai replied on Friday, July 14, 2006

Wbmstrmjb:

I can see how a channel can be written for your own needs

Mike

Hi Mike.

I wish I could understand how to do this. I looked at the Csla code extensively today and couldn't figure out what part Rocky was suggesting I write a custom version of.  Maybe you can clear that up for me?

Thanks.

Wbmstrmjb replied on Friday, July 14, 2006

Xal really helped me out on this one, so I need to give him credit for this, but I'll try to go into more detail.

The DataPortal.Client folder contains the Proxies for different channels.  I am taking the RemotingProxy and creating a DynamicRemotingProxy that will allow for switching between URLs based on data.  Since it is only changing the URL, the Host will still be the RemotingPortal.

I'm changing the CslaDataPortalUrl in the config to be a list of servers that I will parse out.  You could probably do this a few different ways, but a simple parse means that I don't have to change the access method in ApplucationContext.  Inside the new DynamicRemotingProxy class, I have added a DynamicRemotingProxyLocation enumeration to specify the various choices and those are associated to the config file servers.  Here is my code for the changed Portal() method (used to be a property):

private Server.IDataPortalServer Portal(DynamicRemotingProxyLocation location)

{

   string dataPortalURL;

   // still need to parse out the servers

   dataPortalURL = ApplicationContext.DataPortalUrl.ToString();

   if (_portal == null)

      _portal = (Server.IDataPortalServer)Activator.GetObject(typeof(Server.Hosts.RemotingPortal), dataPortalURL);

   return _portal;

}

Now in the methods of the Proxy such as Create, Fetch, Update, I am changing it to look at the object's interfaces to see if it has a new interface that I call IDynamicRemotingHelper.  If so, it will call that function on the object to get the location.  Here is that code for the Update:

public Server.DataPortalResult Update(object obj, Server.DataPortalContext context)

{

   DynamicRemotingProxyLocation location;

   if (obj is IDynamicRemotingHelper)

      location = ((IDynamicRemotingHelper)obj).PortalLocation;

   else

      // my default location

      location = DynamicRemotingProxyLocation.EUR;

   return Portal.Update(obj, context);

}

I hope this helps.  If you need more clarification on an issue, let me know.  When I finish, I will post changes and/or issues that I came across.

razorkai replied on Monday, July 17, 2006

Mike.

This is great!  Exactly the sort of idea I was looking for.  I seem to be missing part of the picture though.  Could you show me an example of how the IDynamicRemotingHelper.PortalLocation method is implemented and also what the DynamicRemotingProxyLocation enum looks like.  Also, how are you parsing out the appropriate Url and what does the relevant section in your config file look like.  Sorry for all the questions <g>.

Thanks!

Wbmstrmjb replied on Monday, July 17, 2006

No problem.  I know sometimes I also can't figure out how certain things work.

First a little background on my environment.  We have 4 offices (I'll call them E, M, BR, and P - abbreviated of course).  Each office could potentially have a portal but for now we just want to add a second.  Currently E has a portal and we're adding P as a second.

The IDyanmicRemotingHelper.PortalLocation would be up to you.  For me I need to base it on data in the object, so if my object Foo implements it and I base it going to a particular location on whether Bar is "sober" or something else, I could implement Portal Location as

public DynamicRemotingProxyLocation PortalLocation()

{

   if (this.Bar == "sober")

      return DynamicRemotingProxylocation.E;

   else

      return DynamicRemotingProxyLocation.P;

}

As for the DynamicRemotingProxyLocation enum, it's just a enum with E, M, BR, and P.  Nothing special.

The URL is up to you how you want to parse it.  Like I said you could probably modify things further and make room for multiple keys in the config file, but I didn't want to change ApplicationContext.  You could just change your key to something like "{E}http://www.locationofE.com:{M}http://www.locationofM.com:{BR}http://www.locationofBR.com:{P}http://www.locationofP.com" and then just parse it with regualr expressions or something similar based on the return of PortalLocation.

Hope this helps!

razorkai replied on Monday, July 17, 2006

Interesting.  My experiments led my down the path of adding to ApplicationContext rather than modifying it.  I have a added a new configuration section, DataPortalURLs to the app.config file.  This is a set of name value pairs i.e. Environment Name and URL.  ApplicationContext then has a new property DynamicDataPortalURLs that retrieves this config section and sets another new property DynamicDataPortalURL by retrieving the corresponding URL from the list that matches the environment the user has selected. 

The beauty of the DynamicRemotingProxy I wrote based on your code is that the changes I have made will only make a difference if the application is specifically set to use the new proxy type.  If it is to use the new type then I simply force the application to specify an environment before allowing any DataPortal calls.  Once the user selects the environment from the list, the selected value is stored in a third new ApplicationContext property.

I now have been told there maybe a requirement for having different forms within an application access different dataportals - Sigh!  On the face of it this doesn't seem impossible as I could just provide some method to reset the proxy object.  However, I am a little concerned of the performance aspect here....  Anyway that is another story.  Many thanks for your help, I think I have an acceptable solution now!

DancesWithBamboo replied on Friday, July 14, 2006

We had this exact same requirement, only with hosted controls in the browser.  The control had to talk back to  he web server environment it was hosted from.  All we did was pass in the url we wanted from the server to the control.  Then the value in the config file was updated with the new url passed in.  It works well and was really easy.  I don't understand Rocky's comment about not being able to change it on the fly...

RockfordLhotka replied on Sunday, July 16, 2006

In the web this would work (sort of) because each time web.config is edited it restarts the web application on the server. This can cause a huge performance problem in larger web sites, since it causes a recompile of the site, along with destruction of the caching, etc...
 
In Windows this won't work because changing the app.config doesn't cause a Windows app to quit and restart (as that would be very disruptive to the user).
 
Rocky


From: DancesWithBamboo [mailto:cslanet@lhotka.net]
Sent: Friday, July 14, 2006 1:23 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] is it possible to change the DataPortalURL in code?

We had this exact same requirement, only with hosted controls in the browser.  The control had to talk back to  he web server environment it was hosted from.  All we did was pass in the url we wanted from the server to the control.  Then the value in the config file was updated with the new url passed in.  It works well and was really easy.  I don't understand Rocky's comment about not being able to change it on the fly...




Copyright (c) Marimer LLC