Title: SynNetWcfAppDomainOnly Description: An example of how to implement WCF services using Synergy .NET while providing the required AppDomain isolation and multi- threading protection needed for Synergy .NET code. This example implements the WCF service directly in code, not via a Synergy .NET Interop project. A different solution would be required in that case. Author: Steve Ives, Synergex Professional Services Group Revision: 1.2 Date: 13th August 2014 Requirements: Synergy .NET 10.1.1c or higher -------------------------------------------------------------------------------- Change history 1.0 Original example. 1.1 Simple bug fix. 1.2 Enhanced the code in the AppDomainProtection assembly to work better when hosted in IIS. -------------------------------------------------------------------------------- There are some special considerations that must be taken into account when executing Synergy .NET code in any multi-threaded environment. Specifically a developer must give special consideration to how the following entities are used within the code, all of which exist at the process level: * Channels * COMMON data * GLOBAL data * STATIC data or other entities * Environment variables In traditional Synergy environments (when compiling with dbl.exe and executing your code with dbr.exe) your code executes in a process that is dedicated to running your program. If other users are running the same code then they are running it in the context of a totally seperate process. This means that each instance of the code has private channels and common data, etc. However, in Synergy .NET it is possible to execute code in environments where multi-threading (running several "threads" of code all within a single process) is supported. Examples of multi-threaded environments include: * Code that you write to execute code in multiple threads * ASP.NET Web applications * Windows Communication Foundation (WCF) services There are two main things that must be considered when running code in any multi-threaded environment: 1. By default code running in all threads share the same Channels, COMMON data, GLOBAL data and STATICs. 2. If the code uses xfServer then it is critical that any given entity of code always executes on the same thread, and the code must execute xcall s_server_thread_init before accessing xfServer. If you want each instance of code to be isolated from all other instances, so that channels, COMMONs, GLOBALs, etc. are unique to that thread, then the way to achieve that is to load each instance of the code into a seperate "AppDomain", and if xfServer is being used then it must also be ensured that each instance of the code always executes on the same thread. The sample code included with this example demonstrates how to do that when implementing a WCF service. IMPORTANT: This example code does not address the issue of environment variables. If your application uses XCALL SETLOG to set environment variables at runtime, and if the values of those environment variables vary (based on user, or some other criteria) then you must implement that functionality in some other way. In Synergy (including Syenrgy .NET) environment variables are always set at the process level, and AppDomain protection DOES NOT CHANGE THAT! IMPORTANT: The instance of Visual Studio that is used to open and run this demo code MUST be "Run as Administrator". If you don't do this then the server application will fail to start because it won't have permissions to bind to your network adapter. The solution has been configured so that when you run the application BOTH the ServiceHost and TestClient applications will be launched. You will see the server applications console window appear almost immediately, but it is normal for the TestClient application to take a few seconds to appear. This is because we're simultaneously launching two applications from one solution, and also because there is generally a brief delay in response from a WCF service the first time a client connects after the service starts. ================================================================================ AppDomainProtection Project The most important code in this example is in the AppDomainProtection project. It has been distributed this way so that you can easily re-use it with your own WCF services. Included in the AppDomainProtection project are: AppDomainPoolManager This class implments a simple pooling mechanism which allows AppDomains to be re-used. This is a way of optimising performance, because creating an AppDomain is a relatively "expensive" operation. BackgroundDispatcher This class controls the processing of background tasks on different threads. IAppDomainPoolable This interface can be implemented by classes whose functionality is to be executed inside an AppDomain pooling environment such as that provided by AppDomainPoolManager. Implementing this interface enables AppDomain pooling, and provides several call-back methods that are called during the lifetime of an object. IsolatableServiceBase This class is a base class to be used for WCF services whose code is to be isolated by being loaded into an AppDomain. ServiceInstanceProvider This class implements a custom provider that will be called by WCF whenever a new instance of the WCF service is required. This functionality is implemented by attributing your WCF service class or interface with SingletonBehaviorAttribute. SingletonBehaviorAttribute This class implements an attribute that can be applied to a WCF service class (or interface) in order to implement a custom WCF service instance provider that provides AppDomain and multi-threading protection for any Synergy .NET code that executes within the service. The custom service instance provider is implemented in the ServiceInstanceProvider class. ================================================================================ PartsSystem Project This project is a Synergy .NET Class Library that essentially contains Synergy business logic and database access code. The code in this class library is called by the code in the WCF service. Most of the code in this project was code generated using CodeGen. The CodeGen templates that were used can be found in the "Templates" solution folder, and the CodeGen commands that were used can be found in the regen.bat batch file in the "Solution Items" solution folder. ================================================================================ WcfServiceLibrary Project This project is again a Synergy .NET class library. It contains classes that "wrap" the business logic in the previous project in a WCF service. Again, most of the code in this project was code generated using CodeGen. ================================================================================ ServiceHost Project This project is a Synergy .NET console application that is used to host the WCF service. To start the service make sure this project is set as the "Startup Project" and then use Debug > Start Without Debugging" to start the service. When you start the service you should see a console window apper, and it should contain text similar to this: The service is ready at http://localhost:56565 Press a key to terminate the service ================================================================================ TestClient Project This project is a very simple Synergy .NET WPF application. It has a service reference to the WCF service exposed by the server solution, and uses some of the WCF services methods ================================================================================ Strong Name Signing If you intend to host your Synergy .NET WCF services in Internet Information Server (IIS) then all assemblies that will be loaded in IIS (in the case of this example that would be AppDomainProtection.dll, PartsSystem.dll and WcfServiceLibrary.dll) must be strong name signed.