DataPortal Remoting Host

Now that we have both Server.DataPortal and ServicedDataPortal .DataPortal built, we need a place for them to run. One option is to have them run in-process with the client code, and that will work right now, with no new code or configuration file required. If we feel the need to have a configuration file at all, it might look like this:

 <?xml version="1.0" encoding="utf-8" ?> <configuration>   <appSettings>     <add key="Authentication" value="CSLA" />   </appSettings> </configuration> 

By not providing URLs for the server-side DataPortal objects, we've told the CSLA .NET framework to run them within the client process.

The other option is to put entries in the client application's configuration file that provide URLs for a remote server where the server-side DataPortal objects will run. This might appear like so:

 <?xml version="1.0" encoding="utf-8" ?> <configuration>   <appSettings>     <add key="Authentication" value="CSLA" />     <add key="PortalServer"         value="http://myserver/DataPortal/DataPortal.rem" />     <add key="ServicedPortalServer"         value="http://myserver/DataPortal/ServicedDataPortal.rem" />   </appSettings> </configuration> 

This tells the client to use a remote service, but we still don't have a way to host our server-side DataPortal on the server. The easiest way to set up a remoting host is to use IIS, because it's basically all ready to do soall we need to do is perform a little configuration. The benefit to this approach is that we gain a lot of IIS features around security, configuration, and management. The drawback is that we can't use the TCP remoting channel, which is the fastest technology provided with the .NET Framework. Instead, we must use the HTTP channel.

Note 

We've already mitigated the performance issue to some degree, since our client-side DataPortal configures the HTTP channel to use the binary formatter. The choice of formatter is far more important than the choice of channel.

The IIS host will be configured to provide access to both Server.DataPortal and ServicedDataPortal.DataPortal , via remoting. The Server.DataPortal assembly will run directly in the host process. The ServicedDataPortal.DataPortal assembly will also run in the host process, but also within COM+. This is because we configured it to use a COM+ library application.

Because both assemblies will run in the same process, we should get very good performance. Calls from the client need to make a network hop to get to the server, but once on the server, there are no further cross-process or cross-network calls required, which is ideal.

It's important to note that each business application may have its own IIS remoting host configured. All the business objects we host within a single DataPortal host will run under the same user account, with the same Web.config file, and so forth. This means they basically share the same environment, configuration, and security.

In many cases, we'll want to isolate different business applications from each other, so they have different database access, different application-specific configuration files, and so forth. To accomplish this, we'll end up creating a DataPortal host for each business application. The following steps discuss how to create such a host. To create other hosts , follow the same steps, but name the IIS project differently and set up the client-side application configuration files so that their URLs point to the appropriate virtual root.

Server-Side DataPortal Host

Creating a remoting host using IIS isn't difficult. Add a new Empty Web Project to our solution, and name it DataPortal . This creates a virtual root on our server that's emptythe project includes no web forms, no web services, no style sheets, nothing. Not even a Web.config file is created. We get a completely clean slate.

Tip 

We now have a lot of things named DataPortal . We have the client-side DataPortal class, the transactional and nontransactional DataPortal objects that provide most of our functionality, and the new DataPortal host, DataPortal . While this can seem confusing, it's important to remember that the business developer only ever sees the client-side DataPortal class. All the rest of the mechanism is hidden within our framework, so the use of the data portal mechanism as a whole is very straightforward.

Referencing CSLA Assemblies

The first thing we need to do is add references to all our CSLA projects. As usual, use the Add Reference dialog as shown in Figure 5-11.

image from book
Figure 5-11: Referencing the CSLA framework projects

This makes these assemblies available to the project, so that we can expose them via remoting. We'll be directly exposing only CSLA.Server.DataPortal and CSLA.Server.ServicedDataPortal , but any business DLLs that we need for our business application will require CSLA.dll , and it in turn requires CSLA.Core.BindableBase.dll .

Adding a Web.config File

To do the job of exposing our assemblies via remoting, we need to do some preparatory work. In a web application, this means using a Web.config file, so choose Project image from book Add New Item to add one that contains some default settings. The next step is to make a couple of changes.

Turn Off Debugging

For performance reasons, we don't want debugging turned on in this project, so change the debug setting to false :

 <compilation         defaultLanguage="c#"  debug="false"  /> 

Even if debug is set to true , it doesn't really help in a remoting host, because we won't be debugging any web pages or web services. This setting won't allow us to debug the DLLs that are being hosted via remoting in any case, so by setting the value to false , we allow ASP.NET to avoid any debugging overhead.

Turn Off Session State

The default in a new Web.config file is that session state is configured to be stored in-process. In our case, however, we don't need session state, because we're not trying to host any web pages (or anything else that would require the concept of session state).

Having session state enabled incurs some overhead on each request from a client, so we want to turn it off. This can be done by changing the <sessionState> element in the Web.config file so that its mode setting is Off :

 <sessionState  mode="Off"  

This turns off session state entirely, avoiding any overhead on each request.

Configuring Remoting

To make our server-side DataPortal objects available via remoting, we need to add a <system.runtime.remoting> element to the Web.config file. This element will include all the information necessary to configure remoting for these classes. Notice that it's outside the existing <system.web> element.

 <?xml version="1.0" encoding="utf-8" ?>    <configuration>  <system.runtime.remoting>        <application>          <service>            <wellknown mode="SingleCall"                       objectUri="DataPortal.rem"                       type="CSLA.Server.DataPortal, CSLA.Server.DataPortal" />            <wellknown mode="SingleCall"                       objectUri="ServicedDataPortal.rem"                       type="CSLA.Server.ServicedDataPortal.DataPortal,                                             CSLA.Server.ServicedDataPortal" />          </service>        </application>      </system.runtime.remoting>  <system.web> 

We're configuring two different classes through the use of two <wellknown> elements, which you first saw being used in Chapter 3. The first configures the nontransactional Server.DataPortal :

 <wellknown mode="SingleCall"                     objectUri="DataPortal.rem"                     type="CSLA.Server.DataPortal, CSLA.Server.DataPortal" /> 

First, this tells remoting to use SingleCall semantics, so a new server-side DataPortal object will be created for each client method call to the server. Then, the objectUri attribute tells remoting that the class can be accessed at the URI DataPortal.rem . This means that the complete URL for the class is http://myserver/DataPortal/ DataPortal.rem. This is the URL we'd put into a client-side configuration file to use this object via remoting.

Finally, the type attribute describes how remoting should find the class. It indicates that the class to find is named CSLA.Server.DataPortal , and that it can be found in an assembly named CSLA.Server.DataPortal . Remoting will therefore look in the bin directory for either CSLA.Server.DataPortal.dll or CSLA.Server.DataPortal.exe to find the class. Since we've referenced the CSLA.Server.DataPortal project, its DLL will automatically be copied into the bin directory by VS .NET

We do the same thing for the transactional DataPortal :

 <wellknown mode="SingleCall"                  objectUri="ServicedDataPortal.rem"                  type="CSLA.Server.ServicedDataPortal.DataPortal,                                        CSLA.Server.ServicedDataPortal" /> 

The fact that this class is running in Enterprise Services makes no difference to our configuration settings, but it does require an extra step to register the DLL with COM+.

Registering ServicedDataPortal

Before our host can call the ServicedDataPortal object, we need to register it in COM+. The .NET runtime will attempt to register any serviced component (such as our ServicedDataPortal ) with COM+ automatically, the first time it's accessed. Unfortunately, the ASP.NET account doesn't have enough security rights to actually do this. That means that any attempt to use the transactional DataPortal will result in an error indicating that the component couldn't be registered in COM+.

We can resolve this by manually registering the assembly with COM+, using the regsvcs.exe command-line utility that we discussed in Chapter 3. Open a Visual Studio command prompt window and navigate to the DataPortal host website's bin directory. Then run regsvcs.exe to register the assembly:

  > regsvcs CSLA.Server.ServicedDataPortal.dll  

This will register the assembly in COM+, making it available for use by the DataPortal host, and thus by any client applications via remoting.

Testing Remoting

At this point, we should be able to test to see whether our configuration is correct. Build the solution to compile all the assemblies. This will also result in copies of our CSLA DLLs being placed into the bin directory of our web application.

We can then open a browser and navigate to the remoting services to get their XML descriptions or WSDL. This can be done by going to the following URLs:

 http://localhost/DataPortal/dataportal.rem?wsdl http://localhost/DataPortal/serviceddataportal.rem?wsdl 

In both cases, we should get back an XML description of the service similar to that shown in Chapter 3. This includes a list of all the methods it exposes and their parameter expectations. If we've somehow misconfigured remoting, then we'll get an error, and we can proceed to debug until the WSDL result is visible in the browser.

Making the DataPortal Useful

At this point, we have a working DataPortal host, but it can't really do anything useful because it has no knowledge of any business DLLs or databases. (We'll create a business DLL in Chapter 7.)

Also, as it stands, it's configured to use our custom, table-based security (which is the default in our framework), but there is no security database. At the very least, we'll want to provide configuration regarding the security database, or change the security to use Windows' integrated security.

We'll also want to provide the DataPortal host with access to our business DLLs at some stage.

Configuring CSLA

First, let's look at how we might configure the CSLA framework for security, and indicate the location of databases that will be used by the framework and/or our business DLLs. In the DataPortal host's Web.config file, we can add an <appSettings> element that will contain our configuration settings. This element is a top-level element, just like <system.web> or <system.runtime.remoting> .

We can configure the server to use Windows' integrated security like this:

 <?xml version="1.0" encoding="utf-8" ?> <configuration>   <appSettings>     <add key="Authentication" value="Windows" />   </appSettings> 

Alternatively, we can use CSLA security, in which case we should provide a connection string to a security database. We'll be using this database entry later in the chapter, when we implement the custom table-based security, so let's put it into Web.config :

  <appSettings>     <add key="Authentication" value="CSLA" />     <add key="DB:Security"          value="data source=localhost;initial catalog=Security;                                     integrated security=SSPI" />   </appSettings>  
Tip 

We'll create the Security database later in the chapter, and you may need to change this connection string to point to the right database server and so on.

Database Connection Strings

As we add business DLLs to our solution, they'll likely make use of other databases, and so we'll likely add other database connection string elements to the configuration file over time. In Chapter 7, for example, we'll add an entry for our example application's database:

 <add key="DB:PTracker"          value="data source=localhost;initial catalog=PTracker;                                       integrated security=SSPI" /> 

Keep in mind that when using CSLA security and remote, server-side DataPortal objects, all the code in the server-side DataPortal will run under the ASP.NET user account. If we then use integrated security to access the database (as shown here), the ASP.NET user account will need security permissions to access the various databases, tables, and stored procedures that will be used by our code.

As an alternative, we can use specific user ID and password combinations in the connection string to access the database, rather than integrated security. This allows us to avoid opening the databases up for use by any ASP.NET application on the server. The unfortunate side effect is that the username and password are stored in plain text in the Web.config file.

If we use Windows' integrated security without anonymous access, all the server-side DataPortal code will run under the impersonated user identity from the client. Microsoft Knowledge Base article 306158 discusses the details of setting up impersonation in ASP.NET. If we use integrated security to access the database, then each user will need the appropriate database permissions.

Microsoft Knowledge Base article 306158 also includes directions for impersonating a specific user account for all ASP.NET worker code, which would include our server-side DataPortal code and our business object code. This requires changes to Web.config , adding a user account to the server, and either changing the ASP.NET user account privileges or changing the account under which all ASP.NET code runs. This approach would allow us to control directly the user account under which all our data access code runs, thus enabling us to set up database security for that particular user account.

In any case, the only way we'll get database connection pooling is if we have some sort of central user ID, be that the ASP.NET account or a specific user ID and password in the connection string. When using per-user logins, we'll get virtually no database connection pooling, which will likely result in poor application performance. Table 5-5 summarizes the options.

Table 5-5: Security Options and Their Impact on Database Connection Pooling

Database Access Option

IIS Configuration

Consequences

Integrated security

Anonymous access (no impersonation)

All database access is done under the ASP.NET account. We get database connection pooling, but the ASP.NET account needs access to our databases. No password values are stored in clear text. [*]

Integrated security

Windows security (impersonation)

All database access is user-specific , so each client identity is used to access the database. We get no real database connection pooling, and database permissions must be granted to the end-user identities that are using the application. No password values are stored in clear text.

Specific user IDs and passwords in connection strings

Either anonymous access or Windows security

Database access is done under the specific user IDs. We get database connection pooling and have better control over which applications can access which databases. Password values are stored in clear text.

Integrated security

Anonymous access (impersonating specific user)

Database access is done under the specific user ID we provide. We get database connection pooling and have better control over which applications can access which databases. [**]

[*] Note that the SERVER\ASPNET account is a local account, so this option won't work if the database is on a separate machine from the web server.

[**] Note that the SERVER\ASPNET account doesn't have permissions to impersonate a specific user by default. Configuration of this option is complex (see Microsoft Knowledge Base article 306158).

Which configuration is appropriate depends on your specific application and environment. As a general rule, I prefer to use specific user ID and password values in my connection strings, since that provides the highest level of control and flexibility, while still enabling database connection pooling for performance.

Tip 

It isn't advisable to use the sa user ID in this case. We should always create application-specific user IDs that have limited access to our database, and use those for application data access.

Throughout the code in this book, however, we'll be using integrated security. This is Microsoft's recommended approach, since it avoids putting user IDs and password values into a clear text file.

Referencing or Installing Business DLLs

As we build business applications, we'll be building DLLs that contain our business classes. If we have a Customer object, its class will be in a DLLperhaps named Customer.dll .

The server-side DataPortal needs access to these business class DLLs. Remember: Server.DataPortal ultimately creates instances of our business objects and calls the appropriate DataPortal_xyz() methods on the object. To do this, the business DLL containing the business object's code must be available to our server-side DataPortal object.

Tip 

Of course, this only applies if we're running the server-side DataPortal remotely. If we're running the server-side DataPortal objects locally in the client process, then the business DLLs only need to be in the local client application's directory. This is the directory where the Windows Forms executable (or, in a web environment, the bin directory of the Web Forms client) resides.

What this means in practical terms is that the business DLL must reside in the bin directory of the DataPortal host website. All code running in the website, including Server.DataPortal , will always look in the bin directory to find any assemblies.

At runtime, we can always copy business DLLs into the bin directory to make them available to the server-side DataPortal . This can be done using Windows Explorer drag-and-drop, xcopy from the command line, or any other means you choose. Alternatively, we can reference the business project from our DataPortal host web project. When the web project is built, it will automatically copy the DLLs into the bin directory, just like we did with the CSLA assemblies.

As a general rule, this second technique isn't a practical solution for business application development, because we don't want our business developers to have the CSLA framework projects open in their individual business application solutions. This will almost certainly lead to unintentional framework changes that might affect (read: cause bugs in) other applications that also use the framework.

Note 

When a business DLL is created or updated, it should therefore be copied into the DataPortal host web application's bin directory. At the same time, the client machines or web servers using the business DLL must be updated to the same version as the DataPortal , or the application will fail.

When we pass business objects by value across the network, the same version of the DLL must exist at both ends of the link. The .NET remoting and serialization technologies perform version checking to make sure they match; if they don't, we'll get a runtime error. Because of this, it's important to synchronize the update of any business DLL so that the DataPortal host and any clients are updated at the same time.

If we're using no-touch deployment to install the application on our client workstations, this is relatively easy to arrange. All we need to do is copy the new versions of the DLLs into the DataPortal host's bin directory at the same time as we copy them into our server directory for no-touch deployment. (See Appendix A for more information about no-touch deployment.) If we have Web Forms clients, all we have to do is copy the new DLLs into the DataPortal host's bin directory at the same time as we copy them into the Web Forms client's bin directory.

The data portal mechanism and data access infrastructure for our framework is now complete and ready for use. We'll make use of it first as we implement the custom table-based security objects in our framework. Then, we'll move on to create the generic name-value collection object that we talked about earlier.



Expert C# Business Objects
Expert C# 2008 Business Objects
ISBN: 1430210192
EAN: 2147483647
Year: 2006
Pages: 111

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net