Laden...

WCF Service Hosting (Windows Service)

Erstellt von Campy vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.329 Views
C
Campy Themenstarter:in
439 Beiträge seit 2008
vor 12 Jahren
WCF Service Hosting (Windows Service)

Hallo zusammen,

ich hoste meine WCF Services mit Hilfe des Service Hosts unter einem Windows Service. Meine Vorgehensweise sieht momentan folgendermaßen aus:


protected override void OnStart(string[] args)
        {
            if (GeneralService_Host != null)
                GeneralService_Host.Close();
            GeneralService_Host = new ServiceHost(typeof(GeneralService));
            GeneralService_Host.Open();
         }

protected override void OnStop()
        {
            if (GeneralService_Host != null)
            {
                GeneralService_Host.Close();
                GeneralService_Host = null;
            }
        }

Muss ich das jetzt wirklich für jeden meiner WCF Services so machen (ca. 20 Stück, wachsende Anzahl), oder geht das noch ein bisschen generischer?

Vielen Dank
Campy

A programmer is just a tool, which converts coffeine into code! 🙂

B
387 Beiträge seit 2005
vor 12 Jahren

Hallo Campy,

ich habe mir für diesen Zweck eine Basisklasse geschrieben, der ich im Prinzip nur noch das Type-Objekt des ServerContracts übergeben und halt ne Url (weil es sich um Webservices handelt). Im Framework-Standard gibts es sowas im Moment meines wissens nicht.

Gruß
Roland

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Campy,

zuerst ein Hinweis: lagere den WCF-Service-Host in eine eigene Assembly aus. Dann startest du vom Windows-Service diesen WCF-Service-Host in der anderen Assembly. Das hat den Vorteil, dass du auch einen Consolen-Host erstellen kannst und somit ist das Debugging leichter.

oder geht das noch ein bisschen generischer?

Per Reflection und Attributen kann das aber vereinfacht werden. Idealerweise erstellst du dir dazu ein Attribut, etwa so eins:


[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class IsServiceAttribute : Attribute
{
	public string UriAddress { get; private set; }
	//---------------------------------------------------------------------
	public IsServiceAttribute(string uriAddress)
	{
		this.UriAddress = uriAddress;
	}
}

Ein beispielhafte WCF-Service-Klasse schaut dann so aus:


[IsService("net.tcp://localhost:8081/myService")]
[IsService("net.pipe://localhost/myService")]
public class MyService : IMyService 
{ 
	....
}

Die WCF-Service-Host-Klasse schaut bei mir dann grob so aus:


namespace gfoidl.XXX.Service
{
	public class XXXService
	{
		private static TraceSource _traceSource;  // für die TraceSource gibts eigene Erweiterungsmethoden
		private List<ServiceHost>  _hosts;
		//---------------------------------------------------------------------
		static XXXService()
		{
			_traceSource = new TraceSource("gfoidl.XXX.Service");
		}
		//---------------------------------------------------------------------
		public void Start(string[] args)
		{
			_traceSource.TraceStart();

			try
			{
				_hosts = GetHosts();
				_hosts.ForEach(h => h.Open());
			}
			catch (Exception ex)
			{
				_traceSource.TraceCritical(ex);
			}
		}
		//---------------------------------------------------------------------
		public void Stop()
		{
			try
			{
				if (_hosts == null) return;		// nur zur Sicherheit
				_hosts.ForEach(h => h.Close());
			}
			catch (Exception ex)
			{
				_traceSource.TraceWarning(ex);
			}

			_traceSource.TraceStop();
		}
		//---------------------------------------------------------------------
		public void ShowEndpointDescription()
		{
			if (_hosts == null) return;		// nur zur Sicherheit
			
			Console.WriteLine();
			foreach (ServiceHost host in _hosts)
			{
				Console.WriteLine(new string('-', 50));
				foreach (ServiceEndpoint se in host.Description.Endpoints)
					Console.WriteLine(
						"A:\t{0}\nB:\t{1}\nC:\t{2}\n\n",
						se.Address,
						se.Binding.Name,
						se.Contract.Name);
			}
		}
		//---------------------------------------------------------------------
		private static List<ServiceHost> GetHosts()
		{
			var hosts = typeof(XXXService).Assembly
				.GetExportedTypes()
				.Where(t => t.GetCustomAttributes(typeof(IsServiceAttribute), false).Length > 0)
				.Select(t => new ServiceHost(
					t,
					t.GetCustomAttributes(typeof(IsServiceAttribute), false)
						.Cast<IsServiceAttribute>()
						.Select(a => new Uri(a.UriAddress))
						.ToArray())
				)
				.ToList();

			return hosts;
		}
	}
}

Hier wird angenommen dass die Services in der selben Assembly liegen, wenn dem nicht so ist müssen die Assemblies irgendwie bekannst gemacht werden. Das könnte auch per einem Assembly-Attribut erfolgen, oder sonst irgendwie, z.B. indem die Typen der Services direkt übergeben werden, etc. Das kannst du dir überlegen 😉

Die Windows-Service-Klasse dann entsprechend so:


using System.ServiceProcess;

namespace gfoidl.XXX.Service.Host
{
	public partial class XXXService : ServiceBase
	{
		private Service.XXXService _XXXService;
		//---------------------------------------------------------------------
		public XXXService()
		{
			InitializeComponent();
		}
		//---------------------------------------------------------------------
		protected override void OnStart(string[] args)
		{
			_XXXService= new Service.XXXService();
			_XXXService.Start(args);
		}
		//---------------------------------------------------------------------
		protected override void OnStop()
		{
			_XXXService.Stop();
		}
		//---------------------------------------------------------------------
		protected override void OnShutdown()
		{
			this.OnStop();
		}
		//---------------------------------------------------------------------
		protected override void OnPause()
		{
			this.OnStop();
		}
		//---------------------------------------------------------------------
		protected override void OnContinue()
		{
			this.OnStart(null);
		}
	}
}

Und der Console-Host:


namespace gfoidl.XXX.Service.ConsoleHost
{
	class Program
	{
		static void Main(string[] args)
		{
			XXXService service = new XXXService();
			service.Start(args);
			service.ShowEndpointDescription();

			Console.WriteLine("\nPress any key to stop the services");
			Console.ReadKey();

			service.Stop();
		}
	}
}

mfG Gü

Speedski, WCF, Host, Servicehost, Service-Host, Attribute, Attribute auslesen, Reflektion

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

C
Campy Themenstarter:in
439 Beiträge seit 2008
vor 12 Jahren

Hallo gfoidl,

vielen Dank! Das ist genau das was ich suche!
Deine Tipps / Antworten sind echt immer super und sehr gut erklärt! Danke!

MFG Campy

A programmer is just a tool, which converts coffeine into code! 🙂

C
Campy Themenstarter:in
439 Beiträge seit 2008
vor 12 Jahren

Hallo,

wenn man wie ich die Endpoints im ConfigurationFile hinterlegt hat, kann man auch folgende GetHosts() - Methode verwenden:

private static List<ServiceHost> GetHosts()
        {
            var hosts = typeof(MyServiceHost).Assembly
                .GetExportedTypes()
                .Where(t => t.GetCustomAttributes(typeof(IsServiceAttribute), false).Length > 0)
                .Select(t => new ServiceHost(t)
                )
                .ToList();

            return hosts;
        }

Das Attribut sieht bei mir dann so aus:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class IsServiceAttribute : Attribute
    {
    }

Evtl wäre das ganze auch was für den Snippet-Bereich (Falls es dort nicht eh schon zu finden ist).

A programmer is just a tool, which converts coffeine into code! 🙂

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Campy,

Evtl wäre das ganze auch was für den Snippet-Bereich (Falls es dort nicht eh schon zu finden ist).

Das gibts noch nicht in den Snippets. Ich lass es aber hier stehen, entsprechend gekennzeichnet hab ich es aber, so dass über die Forensuche hierher gelangt werden kann. Es steht dir aber frei das in den Snippets einzustellen.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

_
227 Beiträge seit 2006
vor 12 Jahren

@gfoidl: wie könnte man (einfach) auch noch den Service im IIS hosten?

C
Campy Themenstarter:in
439 Beiträge seit 2008
vor 12 Jahren

Hallo Daniel,

beim IIS ist das ganze noch viel einfacher.
Hier solltest du alle Informationen finden die du brauchst:
MSDN: Hosten eines WCF-Dienstes

Viele Grüße und einen schönen Sonntag!
Campy

A programmer is just a tool, which converts coffeine into code! 🙂