Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
WCF Service Hosting (Windows Service)
Campy
myCSharp.de - Member



Dabei seit:
Beiträge: 430

Themenstarter:

WCF Service Hosting (Windows Service)

beantworten | zitieren | melden

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!
private Nachricht | Beiträge des Benutzers
Blacal
myCSharp.de - Member



Dabei seit:
Beiträge: 387

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 6.819
Herkunft: Waidring

beantworten | zitieren | melden

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.
Zitat
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!"
private Nachricht | Beiträge des Benutzers
Campy
myCSharp.de - Member



Dabei seit:
Beiträge: 430

Themenstarter:

beantworten | zitieren | melden

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!
private Nachricht | Beiträge des Benutzers
Campy
myCSharp.de - Member



Dabei seit:
Beiträge: 430

Themenstarter:

beantworten | zitieren | melden

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).
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Campy am .
A programmer is just a tool, which converts coffeine into code!
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 6.819
Herkunft: Waidring

beantworten | zitieren | melden

Hallo Campy,
Zitat
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!"
private Nachricht | Beiträge des Benutzers
_daniel_
myCSharp.de - Member



Dabei seit:
Beiträge: 227

beantworten | zitieren | melden

@gfoidl: wie könnte man (einfach) auch noch den Service im IIS hosten?
private Nachricht | Beiträge des Benutzers
Campy
myCSharp.de - Member



Dabei seit:
Beiträge: 430

Themenstarter:

beantworten | zitieren | melden

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!
private Nachricht | Beiträge des Benutzers