2015-06-23 4 views
13

Wie würde eine Person dazu übergehen, die Methode pro Methode einer API aus mehreren Klassen über WCF auszusetzen, ohne ein WCF-Projekt zu verwenden.Server-seitigen WCF-Dienst automatisch aus vorhandener API generieren

Zum Beispiel sagen sie, ich habe folgende

public interface RainfallMonitor 
{ 
    [ExposeToWeb] 
    void RecordRainfall(string county, float rainfallInches); 

    [ExposeToWeb] 
    float GetTotalRainfall(string county); 

    void ClearRainfall(string county); 
} 

Ich verstehe, konnte ich eine WCF-Dienst-Bibliothek wie gewohnt erstellen und nur einen WCF-Dienst namens „RainfallMonitor“ hinzufügen.

Was ich erforsche ist ... ist es möglich/vernünftig, irgendwie den gesamten WCF-bezogenen Code zur Kompilierzeit für eine gesamte API zu generieren, ohne die Klassen WCF-Dienste zu machen. Möglicherweise unter Verwendung von Attributen wie ExposeToWeb, um anzugeben, welche Methoden über die Dienste verfügbar gemacht werden sollen. Die sich ergebende würde so funktionieren:

  1. Klassen in Projekt RainfallAPI
  2. Compile und haben ein weiteres Projekt/dll RainfallService genannt wird automatisch aufgerufen erstellen/ändern.

Im Wesentlichen:

  • Wenn dies möglich ist, was Ansatz könnte ich tatsächlich es umsetzen?
  • Mit welchen schwerwiegenden Fallgruben könnte ich konfrontiert werden?
  • Gibt es eine vorhandene Codebasis, die etwas Ähnliches tut ich in für Inspiration

Zur Klarstellung aussehen könnte: Ich bitte nicht über Auto-Erzeugung des Client-Stub, über die ich fragen Dienste auf der Serverseite zu schaffen.

+2

Ich kann mir zwei mögliche Probleme vorstellen: 1) Methodenüberladungen können nicht 1: 1 auf mehrere OperationContracts abgebildet werden (Namen müssen unterschiedlich sein). 2) Alle in der API verwendeten komplexen Typen müssen serialisierbar sein (z. B. als [DataContracts]), sodass API-Autoren beachten müssen, dass ihre API als WCF-Services verfügbar gemacht wird. – nodots

Antwort

0

Für Ihre Frage zu "Was ich erforsche ist ... ist es möglich/sinnvoll, den gesamten WCF-Code zur Kompilierungszeit für eine gesamte API zu generieren, ohne die WCF-Services tatsächlich zu erstellen" sind Optionen, aber sie werden alle viel Arbeit erfordern.

Sie müssten eine Codegenerierungsanwendung schreiben, die Klassen wie CSharpCodeProvider verwendet (es gibt auch eine für VB) und Reflektion, um Ihre Bibliothek als Post-Build-Schritt zu untersuchen, den gewünschten Code im Speicher zu erstellen und speichern Sie es als DLL ab.

Diese Anwendung muss nach einem benutzerdefinierten Attribut suchen, das angibt, dass es sich um einen WCF-Dienst handeln sollte, und den WCF-Code basierend auf den von Ihnen definierten Regeln ausgeben.

In der Tat müssen Sie Code schreiben mit dem CodeDOM Modell, das über Code auf eine ganz andere Art und Weise nachzudenken erfordert. Nicht jeder kann sein Denken auf diese Ebene abstrahieren.

Beachten Sie, dass Sie mit dem CodeDOM-Modell einige der Probleme, die nodots genannt haben, beheben können, z. B. das Erfordernis einer Serialisierung für Datenverträge. Dies könnte hinzugefügt werden und eine neue DLL würde von Ihrer CodeDOM-basierten Reflexions-Bibliothek ausgegeben werden.

Durch durchdachtes Design und ziemlich viel Arbeit ist es möglich, die von Ihnen gesuchte Leistung zu erreichen. Es ist nur eine dunkle Straße mit vielen Fallstricken, um dorthin zu gelangen.

1

Ich vor kurzem Leiter dieser Bibliothek: Fody.Wie ich es verstehe, ist es möglich, in den Build-Prozess einzudringen und IL in die Baugruppe zu injizieren. Ich bin mir nicht ganz sicher, wie es funktioniert, aber es könnte möglich sein, durch die IL zu suchen, alle Methoden mit dem ExposeToWeb Attribut zu finden und das zu verwenden, um den Vertrag für den WCF-Dienst in der Assembly auszugeben. Wenn Sie der Klasse jedoch bereits Attribute hinzufügen, fügen Sie zunächst die korrekten WFC-Attribute hinzu und verwenden Sie dann SvcUtil, um die Verträge im Post-Build zu generieren.

EDIT: Hier ist ein Beispiel dafür, wie Sie nutzen könnten svcutil:

C#:

[ServiceContract] 
public interface IRainfallMonitor 
{ 
    [OperationContract] 
    void RecordRainfall(string county, float rainfallInches); 
} 

public class RainfallMonitor : IRainfallMonitor 
{ 
    public void RecordRainfall(string county, float rainfallInches) 
    { 
     // code 
    } 
} 

Post build Powershell:

$svcutil = "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\SvcUtil.exe" 
$csc = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe" 
$assembly = "bin/debug/ProjectWithoutWCF.dll" 
$service = "ProjectWithoutWCF.RainfallMonitor" 
$outputns = "ProjectWithoutWCF.RainfallMonitor.Service" 
$outputdir = "bin/debug" 

md svcutil_tmp 
cd svcutil_tmp 

& $svcutil /serviceName:"$service" "../$assembly" 
& $svcutil *.wsdl *.xsd /importxmltypes /out:"output.cs" /n:"*,$outputns" 
& $csc /target:library /out:$outputns.dll "output.cs" 

cp "$outputns.dll" "../$outputdir" 
cp output.config "../$outputdir/$outputns.dll.config" 
cd .. 
rm -r .\svcutil_tmp 

und Sie werden so etwas wie dieses brauchen in Sie Projektkonfiguration:

<system.serviceModel> 
    <services> 
    <service name="ProjectWithoutWCF.RainfallMonitor" > 
     <endpoint address="" binding="basicHttpBinding" contract="ProjectWithoutWCF.IRainfallMonitor"> 
     </endpoint> 
    </service> 
    </services> 
</system.serviceModel> 

Es ist ein wenig fummelig und Sie werden wahrscheinlich einige Anpassungen an das Skript und die Konfiguration benötigen. Aber das Ergebnis ist, dass Sie eine Datei ProjectWithoutWCF.RainfallMonitor.Service.dll mit den WCF-Dienstverträgen haben.

0

Ja, dies kann mit mäßigem Aufwand mit den richtigen Werkzeugen erfolgen. Wenn Sie Visual Studio haben, haben Sie bereits Microsoft T4-Code-Generator. Es ermöglicht Ihnen, Code zu generieren, indem Sie "Textvorlagen" schreiben, die sehr an die RAZOR-Syntax von ASP.NET erinnern. Mit T4 können Sie tatsächlich vorhandene Klassen instanziieren und mithilfe von Reflektion alle Klassennamen und Methodensignaturen lesen und schließlich Ihre WCF-Dienste generieren. Es ist nicht so schwer!

Hier ist eine Probe T4-Vorlage aus Oleg Sych's tutorial:

<#@ template language=“C#v3.5” #> 
<#@ output extension=“SQL” #> 
<#@ assembly name=“Microsoft.SqlServer.ConnectionInfo” #> 
<#@ assembly name=“Microsoft.SqlServer.Smo” #> 
<#@ import namespace=“Microsoft.SqlServer.Management.Smo” #> 
<# 
    Server server = new Server(); 
    Database database = new Database(server, “Northwind”); 
    Table table = new Table(database, “Products”); 
    table.Refresh(); 
#> 
create procedure <#= table.Name #>_Delete 
<# 
    PushIndent(”\t”); 
    foreach (Column column in table.Columns) 
    { 
     if (column.InPrimaryKey) 
      WriteLine(”@” + column.Name + ” ” + column.DataType.Name); 
    } 
    PopIndent(); 
#> 
as 
    delete from <#= table.Name #> 
    where 
<# 
    PushIndent(”\t\t”); 
    foreach (Column column in table.Columns) 
    { 
     if (column.InPrimaryKey) 
      WriteLine(column.Name + ” = @” + column.Name); 
    } 
    PopIndent(); 
#> 

Die Ausgabe würde wie folgt aussehen:

create procedure Products_Delete 
    @ProductID int 
as 
    delete from Products 
    where ProductID = @ProductID 

Natürlich Ihr Beispiel Sie Reflexion auf Ihrer vorhandene Klassenbibliothek verwenden würden, anstatt von SQL-Abfragen. Die WCF-Dienste, die Sie generieren, können einfach Ihre vorhandene Bibliothek aufrufen, sodass Sie nicht die gesamte Domänenlogik kopieren müssen.

MSDN

https://msdn.microsoft.com/en-us/library/bb126445.aspx

Verwandte Themen