2015-06-23 19 views
13

W jaki sposób osoba może ujawnić metodę dla metody API składającej się z kilku klas za pośrednictwem WCF bez użycia projektu WCF.Generowanie usługi WCF po stronie serwera automatycznie z istniejącego interfejsu API

Na przykład, powiedzmy, że mam następujące

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

    [ExposeToWeb] 
    float GetTotalRainfall(string county); 

    void ClearRainfall(string county); 
} 

Rozumiem mogę utworzyć bibliotekę usług WCF jak zwykle i po prostu dodać usługę WCF nazwie „RainfallMonitor”.

Co badam jest ... jest to możliwe/uzasadnione, aby w jakiś sposób wygenerować cały kod związany z WCF w czasie kompilacji dla całego API bez faktycznego wykonywania usług WCF klas. Być może za pomocą atrybutów, takich jak ExposeToWeb, można wskazać metody, które należy ujawnić za pośrednictwem usług. Powstały będzie funkcjonować tak:

  1. Tworzenie/modyfikowanie klas w projekcie o nazwie RainfallAPI
  2. kompilacji i mieć inny projekt/dll generowane nazywa RainfallService automatycznie.

Zasadniczo:

  • Jeśli jest to możliwe, co podejście mogę podjąć, aby rzeczywiście wdrożyć go?
  • Do jakich poważnych pułapek mogłem wpaść?
  • Czy istnieje istniejących codebase że robi coś podobnego mógłbym zajrzeć do inspiracji

Dla wyjaśnienia: Nie pytam o auto-generowanie niedopałek klienta, pytam o tworzeniu usług po stronie serwera.

+2

Mogę wymyślić dwa potencjalne problemy z mojej głowy: 1) Przeciążenia metod nie można odwzorować 1: 1 na wiele operacji ContractContracts (nazwy muszą być różne). 2) Wszystkie typy złożone używane w interfejsie API muszą być przekształcalne do postaci szeregowej (na przykład [Kontakty danych]), więc autorzy interfejsów API muszą mieć świadomość, że ich interfejs API zostanie ujawniony jako usługi WCF. – nodots

Odpowiedz

0

Na twoje pytanie dotyczące "Co odkrywam jest ... jest to możliwe/uzasadnione, aby w jakiś sposób wygenerować cały kod związany z WCF w czasie kompilacji dla całego API bez faktycznego wykonywania usług WCF klas.", Nie są opcje, ale wszystkie będą wymagały dużo pracy.

Musisz napisać aplikację/bibliotekę do generowania kodu, która wykorzystuje klasy takie jak CSharpCodeProvider (jest także jedna dla VB) i refleksję, aby sprawdzić bibliotekę jako krok budowania postu, zbuduj kod, który chcesz w pamięci i zapisz go jako bibliotekę DLL.

Ta aplikacja musiałaby znaleźć utworzony atrybut niestandardowy, który wskazuje, że powinna to być usługa WCF, i wyprowadzać kod WCF w oparciu o zdefiniowane reguły.

W efekcie trzeba napisać kod za pomocą modelu CodeDOM, który wymaga myślenia o kodzie w znacznie inny sposób. Nie każdy jest w stanie rozwinąć swoje myślenie na ten poziom.

Należy pamiętać, że korzystając z modelu CodeDOM, można przezwyciężyć niektóre problemy, o których wspomniały nodots, takie jak wymóg serializacji dla umów danych. To może być dodane i nowa biblioteka DLL powinna być wyprowadzana przez twoją bibliotekę refleksyjną opartą na CodeDOM.

Dzięki przemyślanemu projektowi i sporym nakładom pracy możliwe jest osiągnięcie pożądanego rezultatu. To tylko mroczna droga z mnóstwem pułapek, aby się tam dostać.

1

Niedawno szef tej biblioteki: Fody.Jak rozumiem, pozwala to na dołączenie do procesu budowania i wstrzyknięcie IL do zespołu. Nie jestem do końca pewien, jak to działa, ale możliwe jest przeszukiwanie IL, znajdowanie wszystkich metod za pomocą atrybutu ExposeToWeb i używanie go do emisji kontraktu dla usługi WCF w zespole.

Ale z drugiej strony, jeśli dodajesz już atrybuty do klasy, dlaczego nie wystarczy po prostu dodać poprawne atrybuty WFC, a następnie użyć SvcUtil do wygenerowania kontraktów w kompilacji pocztowej?

EDIT: Oto przykład jak można użyć 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 
    } 
} 

po kompilacji 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 

i trzeba będzie coś takiego w konfiguracja projektu:

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

Jest to trochę skrzypiące i najprawdopodobniej będziesz potrzebować ulepszenia skryptu i konfiguracji. Ale wynik jest taki, że masz plik ProjectWithoutWCF.RainfallMonitor.Service.dll z umowami serwisowymi WCF.

0

Tak, można to zrobić przy umiarkowanym wysiłku przy użyciu odpowiednich narzędzi. Jeśli masz Visual Studio, masz już generator kodu T4 Microsoftu. Umożliwia generowanie kodu poprzez pisanie "szablonów tekstowych", które bardzo przypominają składnię RAZOR ASP.NET. Korzystając z T4, można faktycznie utworzyć instancje istniejących klas i użyć odbicia, aby odczytać wszystkie nazwy klas i sygnatury metod, a ostatecznie wygenerować usługi WCF. To nie jest takie trudne!

Oto próbka T4 szablon z 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(); 
#> 

Wyjście będzie wyglądać następująco:

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

Oczywiście, Twój przykład, można użyć refleksji na istniejącej biblioteki klas zamiast zapytań sql. Usługi WCf, które generujesz, mogą po prostu wywoływać istniejącą bibliotekę, dzięki czemu nie musisz kopiować całej rzeczywistej logiki domeny.

MSDN

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