Initialize Server-Side Code - Object Factory

Initialize Server-Side Code - Object Factory

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


Kevin Fairclough posted on Tuesday, September 14, 2010

Hi

I need to call some code that will intialize certain server-side responsibilites.  These calls require assemblies that are not referenced from my main application as I am using ObjectFactory so I cannot use the entry point in WPF app.cs. 

The question is where do I put this code?

Regards

Kevin

 

rfcdejong replied on Tuesday, September 14, 2010

First of all: if u have only 1 tier u need to have all te assemblies in one output directory, it's easy to reference them all from your main (frontend) project.
If u have a server tier then u don't need them in your main project, just reference them in your server app.

For your initialization u have several possible solutions:

1) per call / factory, if u look at Csla.Server.FactoryDataPortal u'll see that each call does "Invoke" and then the factory method (create, fetch, update, delete) u can use this Invoke method todo
2) per session or single host or even for per call in wcf as create own ServiceHost and a an ServiceHostFactory and override the InitializeRuntime()

Kevin Fairclough replied on Tuesday, September 14, 2010

Thanks for the reply.  I need to do this once for the lifetime of the application.

So In my Wpf app.cs I need to scan for assemblies and somehow call the code dynamically, as I cannot add a reference to my data assembly.  Foreach server-side technology I need to hook into the startup event and run it there.

If only there was a hook inside Dataportal Server that allowed me to add a static class to my Data assembly which would be called once the DataPortal is requested (Server-side).  Then I could put the code there and not have to write code in the front end or foreach backend.

Kevin

 

 

JonnyBee replied on Tuesday, September 14, 2010

The problem of initializing server side code is more complex than this.

1. Server side code is a multithreaded server (typically running under IIS or AppFabric). If initalizing code was to run at the first DataPortal call you would have to lock the code to prevent new threads/requests from running the initializing code.

2. ServerSide ApplicationPool may be recycled at any given point depending on IIS configuration.

You could achieve 1) by hooking on to the "CslaAuthorizationProvider" which is always called once for each serverside DataPortal cal, even tho' it is not intended for this purpose.

Kevin Fairclough replied on Tuesday, September 14, 2010

JonnyBee

The problem of initializing server side code is more complex than this.

1. Server side code is a multithreaded server (typically running under IIS or AppFabric). If initalizing code was to run at the first DataPortal call you would have to lock the code to prevent new threads/requests from running the initializing code.

2. ServerSide ApplicationPool may be recycled at any given point depending on IIS configuration.

You could achieve 1) by hooking on to the "CslaAuthorizationProvider" which is always called once for each serverside DataPortal cal, even tho' it is not intended for this purpose.

Surely if its static, or done in a static constructor it will be ok?

rfcdejong replied on Tuesday, September 14, 2010

The hook is available when the servicehost is created, write a custom servicehostfactory and create an custom servicehost.

public class MyServiceHost : ServiceHost
{
  public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
    : base(serviceType, baseAddresses) { }
 
  protected override void InitializeRuntime()
  {
    .. here your init..
  }
// if u want  protected override void OnOpening... 
// if u want  protected override void OnClosing...
// if u want  protected override void OnFaulted..
}

public class MyServiceHostFactory : ServiceHostFactory 
{
  protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
  {
    return new MyServiceHost(serviceType, baseAddresses);
  }
}

and in WcfPortal.svc

<%@ ServiceHost Factory="namespace.MyServiceHostFactory" Service="Csla.Server.Hosts.WcfPortal" %>

Kevin Fairclough replied on Tuesday, September 14, 2010

rfcdejong

The hook is available when the servicehost is created, write a custom servicehostfactory and create an custom servicehost.

public class MyServiceHost : ServiceHost
{
  public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
    : base(serviceType, baseAddresses) { }
 
  protected override void InitializeRuntime()
  {
    .. here your init..
  }
// if u want  protected override void OnOpening... 
// if u want  protected override void OnClosing...
// if u want  protected override void OnFaulted..
}

public class MyServiceHostFactory : ServiceHostFactory 
{
  protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
  {
    return new MyServiceHost(serviceType, baseAddresses);
  }
}

and in WcfPortal.svc

<%@ ServiceHost Factory="namespace.MyServiceHostFactory" Service="Csla.Server.Hosts.WcfPortal" %>

If it's not configured for n-tier then WCF will not be used,  I would have preferred to put it in only one place and forget about it.  If DataPortal.Server had an Init I could hook up to (by creating a static class in my data assembly) then it would be the same for all server DataPortal configurations, or is this not possible or practical?

 

 

tmg4340 replied on Tuesday, September 14, 2010

I'm a little confused... if your app isn't n-tier, why are you worrying about "server side responsibilities"?  Or are you trying to cover all the possible installations of your app, some of which may be n-tier and some may not?  That would seem to invite problems, but...

In any event, let's touch on what we can.

1. Having your initialization code in a static constructor or static class does not automatically make it thread-safe.  You must write code to make it so (or apply the appropriate attributes to your class/methods).  It's not hard to do unless you have serious performance/scalability issues to contend with.

2. Rocky has touched on this before, because it is a thorny problem for the reasons JonnyBee mentioned.  The technique JonnyBee mentioned is, I believe, the one technique Rocky has offered up as a possible solution.  Otherwise, I'm pretty sure you're out of luck on the server side.

HTH

- Scott

Kevin Fairclough replied on Wednesday, September 15, 2010

Yes my app may be configured differently, either local or n-tier.  That was one of my main reasons for choosing CSLA in the first place.

What I dont understand is; I was under the impression that a static constructor is threadsafe so why is this a problem.

 

RockfordLhotka replied on Wednesday, September 15, 2010

Even if you use a static constructor, something has to touch a static member of that specific type to trigger the cctor to run. So you'd still need some bit of code that you know will touch a static member of that type on every data portal request.

So the answer still comes back to implementing an "authorizer", because that's the one place you know will be invoked on every call.

Kevin Fairclough replied on Wednesday, September 15, 2010

Ok, I will mark it as an answer.  It would be nice if Csla allowed for an Initializer that called an Initialize method, at least then my code would look like its in the correct place.

 

 

 

 

RockfordLhotka replied on Wednesday, September 15, 2010

Yes, I should have named the "authorizer" with a broader name. When I added the feature I was solving a specific issue with authorization, but of course it is possible to do many other things at that point in the process flow. At some point I suppose I'll have to fix that - breaking everyone who uses the feature. Or maybe add a second step in the workflow:

  1. Initialize
  2. Authorize
  3. Run server-side data portal

For example, the "authorizer" is also a good place to initialize an IoC container, or establish important server-side ApplicationContext values.

It would also be ideal to have a post-processing hook - something that is invoked after all server processing is complete (other than final serialization of the results) for each call.

  1. Initialize
  2. Authorize
  3. Run server-side data portal
  4. Complete

 

Kevin Fairclough replied on Thursday, September 16, 2010

Sounds perfect.

Thanks everyone for your help.

Kevin

Copyright (c) Marimer LLC