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