Content by Category
.NET 1.x
.NET 2.0
.NET 3.0
.NET 3.5
.NET 4.0
.NET Assemblies
.NET Framework
.NET Getting Started
Accessibility
ADO.NET
Advertorials
Agile Development
AJAX
Architecture
ASP.NET
ASP.NET MVC
ASP.NET WebForms
Azure
B2B (Business Integration)
Bing
BizTalk
Book Excerpts
Build and Deploy
C#
C++
ClickOnce
Cloud Computing
Code Contracts
CODE on the Road!
COM+
Community
Conferences
Continuous Integration
Crystal Reports
CSLA.NET
CSS
Data
Design Patterns
Development Process
Display Technologies
Distributed Computing
DotNetNuke
DSL
Dynamic Programming
Editorials
Enterprise Services ("COM+")
Entity Framework
Events
Expression Blend
F#
Fox to Fox
Frameworks
Functional Programming
Git
Graphics
Internet Explorer 8.0
Interviews
iPhone
Iron Ruby
Java
Java Script
jQuery
LINQ
Linux
Mac OS X
MDX
Microsoft Application Blocks
Microsoft Business Rules Framework
Microsoft Dynamics
Microsoft Expression
Microsoft Office
Mobile Development
Mobile PC
Mono
MsBuild
Network
NHibernate
Object Oriented Development
Open Source
Opinion
Opinions
Oracle
ORM
Other Languages
Parallel Programming
Patterns
Podcasts
Post Mortem
PowerPoint
Print/Output
Product News
Product Reviews
Project Management
Python
Q&A
Rails
Rake
Reporting Services
REST
RIA Services
Ruby
Ruby on Rails
Search
Security
Services
SharePoint
Silverlight
SOA
Social Networks
Software & Law
Software Business
Source Control
Speech-Enabled Applications
SQL Server
SQL Server 2000
SQL Server 2005
SQL Server 2008
SQL Server CE/AnyWhere/Mobile/Compact
Subversion
Sync Framework
Tablet PC
TDD
Team System
Techniques
Testing and Quality Control
Tips
UI Design
UML
User Groups
VB Script
VB.NET
Version Control
VFP and .NET
VFP and SQL Server
Virtual Earth
Vista
Visual Basic
Visual Basic 6 (and older)
Visual FoxPro
Visual Studio .NET
Visual Studio 2005
Visual Studio 2008
Visual Studio 2010
Visual Studio Tools for Office
VSX
WCF
Web Development (general)
Web Services
WF
Whitepapers
Windows 7
Windows Azure
Windows Live
Windows Server
Windows Vista
WinForms
Workflow
WPF
XAML
XML
XNA
XSLT



CODE Training


 


CODE TRAINING


Reader rating:
Click here to read 19 comments about this article.
Article source: CoDe (2007 - Jan/Feb)


Article Pages: < Previous - 1 2  3  4 5 6 - Next >


Hosting WCF Services (Cont.)

Self-Hosting

Self-hosting is the simplest way to host your services-and the approach that yields the least number of hosting features. As the label implies, self-hosting requires you to write the code necessary to initialize the ServiceHost and manage its lifetime. At a minimum you provide a managed process, instantiate a ServiceHost for each service, and then initialize and open them to provide a communication channel for each endpoint to receive incoming messages.

"
“Windows services are the most useful of the self-hosting environments for WCF services. In fact, for services deployed in a production server system, Windows services are the only practical self-hosting choice…”
"

Typically you’ll keep ServiceHost instances alive for the lifetime of the application in which they are hosted. Once you open the ServiceHost, the service model allocates a worker thread to process each incoming request to its respective service endpoints. Your job is to keep the application alive as long as you want to service those requests. Any managed application process will suffice including console, Windows Forms, WPF, or managed Windows services as I discussed earlier.

In this section, I’ll walk you through the relevance of these self-hosting environments including scenarios where they are most applicable.

Console Applications

Console applications are a popular hosting environment for developing and testing services. As I discussed earlier, you need only create and open the ServiceHost instance and keep the console process alive to receive and process requests. Listing 1 illustrates this.

A console application is ultimately impractical for deploying production services for a few reasons:

  • It requires a user be logged in to the machine to start the process
  • The console can be easily closed taking the communication channel along with it

Still, you can expect to see plenty of console hosts in sample code you download for WCF, and you will likely use them to execute rudimentary tests on your services.

Windows Applications

Both Windows Forms and WPF applications can host WCF services associated with an application interface. These scenarios might warrant this arrangement:

  • Chat applications that participate in a peer mesh will expose services to receive broadcast messages.
  • Client applications may host services in-process to consume local services without crossing a process boundary. For example, a smart client application may use local services when operating offline and remote services while online (Figure 2).
  • Services deployed to client or server machines may have an associated user interface if the service presents an activity log or provides some administrative controls for service activation and deactivation.

Click for a larger version of this image.

Figure 2: A Windows client hosting in-process WCF services for offline work, and consuming remote WCF services over the Web while online.

Unlike console hosting, you can program a Windows application to avoid accidental shutdown with dialog box interaction. However, these applications do require a user to be logged in to start the application-and this limits their usefulness in server deployments. Managed Windows services solve this problem, and may sometimes incorporate a user interface, so it is still important to understand the concurrency implications of hosting services when UI threads are involved.

A simple way to host services in a Windows application is to process requests on the UI thread. This means that the application processes requests through the Windows message loop, one at a time. In fact, this is the default behavior if you construct the ServiceHost instance while running on the UI thread. For example, the following code illustrates constructing the ServiceHost in the Form constructor for a Windows Forms application:

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
    localhost.HelloIndigoServiceClient proxy = new 
localhost.HelloIndigoServiceClient();
  }

  // other code
}

You can verify that the service is running on the UI thread by checking the Application.MessageLoop property:

Debug.Assert(Application.MessageLoop);

While running on the message loop, service operations can freely interact with the user interface, setting control and Form properties and so forth. The downside is that the message loop acts as a throttle for message processing-even if the service were to allow multiple concurrent requests.

From the same Windows Form application if you were to construct the ServiceHost instance before starting the UI thread, it will run on its own thread. That means worker threads allocated from the thread pool process messages instead of the message loop. Thus, services can truly process multiple concurrent requests.

One way to achieve this is to construct the ServiceHost during the Main() entry point for the Windows application, before invoking Application.Run() as shown in Listing 2. You can see in the listing that the application also handles the Application.Exit event to properly dispose of the ServiceHost instance. The lifetime of the ServiceHost in this example is the duration of the application, not tied to a particular Form instance. Closing the ServiceHost disposes the ServiceHost instance along with the thread in which it was executed. In that case the application must recreate and open the ServiceHost in order to receive subsequent requests.

Processing requests on the UI thread is not practical for services that require decent throughput on the server. In fact, it is unlikely that a service that processes significant requests will even have a UI associated with it. However, assuming you did want to attempt throughput and UI, you can configure your services to run on a separate thread by setting the UseSynchronizationContext property to false for the ServiceBehaviorAttribute.

[ServiceBehavior(UseSynchronizationContext=false)]
public class HelloIndigoService : 
IHelloIndigoService
{
  // service implementation
}

The default value for this property is true, which means that services will join the UI thread if the ServiceHost is constructed on that thread. By setting this attribute to false your service will always process requests on worker threads from the thread pool-regardless of where the application constructs the ServiceHost.

Accepting requests on multiple threads introduces the potential for concurrency issues when service operations or downstream code must interact with UI or shared resources. Since the UI will always be running on another thread, you can’t directly interact with control or Form properties. Each control (including the Form) has an InvokeRequired property that is set to true when the current thread is not the same as the UI thread that owns the control. When true, you can use the same control’s Invoke() method to invoke any members exposed by the control.

Listing 3 shows a service implementation that posts messages to a Windows Form when you call its SendMessage() operation. In this case, the service is coupled to the user interface, so the static constructor of the service type creates the Form and shares it between all running instances of the service. If you close or dispose of the Form each service instance recreates the Form on demand. Although not shown in this reduced listing (the code sample has a complete implementation) the service type also provides a public ShowForm() method so that the host application can control the Form’s visibility.

When you call SendMessage(), it is running on a separate thread from the Form. The Form exposes a public method, AddMessage(), which encapsulates the check for InvokeRequired before adding the string to the ListBox control:

public void AddMessage(string message)
{
  if (this.InvokeRequired)
  {
    MethodInvoker del = delegate 
      {
        this.listBox1.Items.Add(message);
      };
    this.Invoke(del);
  }
  else
    this.listBox1.Items.Add(message);
}

In a multithreaded environment, you must write code like this for all communication with control and Form properties and methods. You can simplify this by encapsulating the functionality in the Form or in custom thread-safe controls.

Aside from Form and control properties, you must also protect other shared resources when you allow multiple threads into the service. For example, Listing 3 illustrates the use of the lock() statement to protect access to the shared m_form reference. This statement applies a global lock to the Form instance such that only one thread at a time can be interacting with any of its properties or methods. There are other advanced synchronization techniques to increase throughput, such as Mutex, Semaphore, and other WaitHandle types from the System.Threading.WaitHandle namespace.

Aside from throughput considerations that drive your decision to host services on the UI thread, or provide multithreading support and manage concurrency, you should consider the following guidelines for Windows application hosting:

  • Decouple service and host implementation where possible, so that the service code is not tied to a single host implementation.
  • Where possible, the host should only provide UI related to hosting-that is, UI to control the ServiceHost instance-not UI specific to the service functionality. Avoid having services talk directly to host process UI.
  • If the service is associated with UI, encapsulate the creation and display of this UI in the service assembly, not the host. This reduces coupling between service and host. If applicable, services can provide a mechanism for hosts to interact with service UI.
&


Listing 2: Initializing the ServiceHost on a separate thread in a Windows Forms application host
[STAThread]
static void Main()
{
  Application.ApplicationExit +=new 
EventHandler(Application_ApplicationExit);
  Program.MyServiceHost = new 
ServiceHost(typeof(HelloIndigo.HelloIndigoService));
  Program.MyServiceHost.Open();
            
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  Application.Run(new Form1());
}

static void Application_ApplicationExit(object sender, EventArgs e)
{
  if (Program.MyServiceHost!=null)
  {
    Program.MyServiceHost.Close();
    Program.MyServiceHost=null;
  }
}


Listing 3: A service implementation that interacts with a Windows Form
[ServiceBehavior(UseSynchronizationContext=false)]
public class UIService : IUIService
{
  private static ServiceForm m_form;

  private static void CreateForm()
  {
      if (m_form==null || m_form.IsDisposed)
        m_form= new ServiceForm();
  }

  static UIService()
  {
    m_form = new ServiceForm();
    m_form.FormClosed +=new 
System.Windows.Forms.FormClosedEventHandler(m_form_FormClosed);
  }

  static void m_form_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
  {
    lock(m_form)
    {
      m_form = null;
    }
  }

  public void SendMessage(string message)
  {
    CreateForm();
    m_form.AddMessage(message);
  }
}


Article Pages: < Previous - 1 2  3  4 5 6 - Next Page: 'Managed Windows Services' >>

Page 1: Hosting WCF Services
Page 2: Declarative Configuration
Page 3: Self-Hosting
Page 4: Managed Windows Services
Page 5: Message-Based Activation
Page 6: IIS 7.0 and WAS Hosting

How would you rate the quality of this article?
1 2 3 4 5
Poor      Outstanding

Tell us why you rated the content this way. (optional)

Average rating:
3.1 out of 5

177 people have rated this article.

      DevConnections

 

DevReach