Dienstvorgänge (WCF Data Services)
WCF Data Services ermöglicht es Ihnen, Dienstvorgänge für einen Datendienst zu definieren, um Methoden auf dem Server verfügbar zu machen. Wie andere Datendienstressourcen werden Dienstvorgänge durch URIs adressiert. Dienstvorgänge ermöglichen es Ihnen, die Geschäftslogik in einem Datendienst verfügbar zu machen, z. B. um Validierungslogik zu implementieren, rollenbasierte Sicherheit anzuwenden oder spezielle Abfragefunktionen verfügbar zu machen. Dienstvorgänge sind Methoden, die der Datendienstklasse hinzugefügt wurden, die sich von DataService<T> ableitet. Wie alle anderen Datendienstressourcen können Sie Parameter für die Dienstvorgangsmethode angeben. Der folgende Dienstvorgang-URI (auf Grundlage des Schnellstart-Datendiensts) übergibt z. B. den Wert London an den city-Parameter:
https://localhost:12345/Northwind.svc/GetOrdersByCity?city='London'
Die Definition für diesen Dienstvorgang lautet wie folgt:
<WebGet()> _
Public Function GetOrdersByCity(ByVal city As String) As IQueryable(Of Order)
[WebGet]
public IQueryable<Order> GetOrdersByCity(string city)
Sie können mit der CurrentDataSource des DataService<T> direkt auf die Datenquelle zugreifen, die der Datendienst verwendet. Weitere Informationen finden Sie unter Gewusst wie: Definieren eines Dienstvorgangs (WCF Data Services).
Informationen zum Aufrufen eines Dienstvorgangs über eine .NET Framework-Clientanwendung finden Sie unter Aufrufen von Dienstvorgängen und -aktionen (WCF Data Services).
Anforderungen für Dienstvorgänge
Beim Definieren von Dienstvorgängen für den Datendienst gelten folgende Anforderungen. Wenn eine Methode diese Anforderungen nicht erfüllt, wird sie nicht als Dienstvorgang für den Datendienst verfügbar gemacht.
Der Vorgang muss eine öffentliche Instanzmethode sein, die ein Member der Datendienstklasse ist.
Die Vorgangsmethode akzeptiert möglicherweise nur Eingabeparameter. Auf im Nachrichtentext gesendete Daten kann nicht vom Datendienst zugegriffen werden.
Wenn Parameter definiert wurden, muss der Typ eines jeden Parameters primitiv sein. Beliebige Daten eines nicht primitiven Typs müssen serialisiert werden und in einen Zeichenfolgenparameter übergeben werden.
Die Methode muss einen der folgenden Werte zurückgeben:
void (Nothing in Visual Basic)
Ein Entitätstyp im Datenmodell, das der Datendienst verfügbar macht.
Eine primitive Klasse wie eine ganze Zahl oder Zeichenfolge.
Um Abfrageoptionen wie Sortieren, Paging und Filtern zu unterstützen, sollten die Methoden der Dienstvorgänge IQueryable<T> zurückgeben. Anforderungen an Dienstvorgänge, die Abfrageoptionen einschließen, werden für Vorgänge abgelehnt, die nur IEnumerable<T> zurückgeben.
Um den Zugriff auf verknüpfte Entitäten mit Navigationseigenschaften zu unterstützen, muss der Dienstvorgang IQueryable<T> zurückgeben.
Die Methode muss mit dem Attribut [WebGet] oder [WebInvoke] versehen sein.
[WebGet] aktiviert die aufzurufende Methode mit einer GET-Anforderung.
[WebInvoke(Method = "POST")] aktiviert die aufzurufende Methode mit einer POST-Anforderung. Andere WebInvokeAttribute-Methoden werden nicht unterstützt.
Ein Dienstvorgang kann mit dem Attribut SingleResultAttribute versehen sein, das festlegt, dass der Rückgabewert der Methode eine einzige Entität und keine Auflistung von Entitäten ist. Dieser Unterschied schreibt die resultierende Serialisierung der Antwort und die Weise vor, in der zusätzliche Navigationseigenschaftendurchläufe im URI dargestellt werden. Mit der AtomPub-Serialisierung wird z. B. ein einzelner Ressourcentyp als Eingangselement und eine Gruppe von Instanzen als Feed-Element dargestellt.
Adressierung von Dienstvorgängen
Sie können Dienstvorgänge adressieren, indem Sie den Namen der Methode im ersten Pfadsegment eines URI platzieren. Als Beispiel greift der folgende URI auf einen GetOrdersByState-Vorgang zu, der eine IQueryable<T>-Auflistung von Orders-Objekten zurückgibt.
https://localhost:12345/Northwind.svc/GetOrdersByState?state='CA'&includeItems=true
Wenn Sie einen Dienstvorgang aufrufen, werden Parameter als Abfrageoptionen angegeben. Der vorherige Dienstvorgang akzeptiert sowohl einen Zeichenfolgenparameter state als auch einen booleschen Parameter includeItems, die angeben, ob zugehörige Order_Detail-Objekte in die Antwort einbezogen werden.
Nachfolgend sind gültige Rückgabetypen für einen Dienstvorgang aufgeführt:
Gültige Rückgabetypen |
URI-Regeln |
---|---|
void (Nothing in Visual Basic) -oder- Entitätstypen -oder- Primitive Typen |
Der URI muss ein einzelnes Pfadsegment sein, das den Namen des Dienstvorgangs trägt. Abfrageoptionen sind nicht zulässig. |
Der URI muss ein einzelnes Pfadsegment sein, das den Namen des Dienstvorgangs trägt. Da der Ergebnistyp kein IQueryable<T>-Typ ist, sind keine Abfrageoptionen zulässig. |
|
Abfragepfadsegmente zusätzlich zum Pfad, der der Name des Dienstvorgangs ist, sind zulässig. Abfrageoptionen sind ebenfalls zulässig. |
In Abhängigkeit vom Rückgabetyp des Dienstvorgangs können dem URI zusätzliche Pfadsegmente oder Abfrageoptionen hinzugefügt werden. Beispielsweise greift der folgende URI auf einen GetOrdersByCity-Vorgang zu, der eine IQueryable<T>-Auflistung von Orders-Objekten, sortiert nach RequiredDate in absteigender Reihenfolge, zusammen mit den verknüpften Order_Details-Objekten zurückgibt:
https://localhost:12345/Northwind.svc/GetOrdersByCity?city='London'&$expand=Order_Details&$orderby=RequiredDate desc
Zugriffssteuerung für Dienstvorgänge
Dienstweite Sichtbarkeit der Dienstvorgänge wird durch die SetServiceOperationAccessRule-Methode in der IDataServiceConfiguration-Klasse gesteuert, und zwar auf ähnliche Weise, wie die Sichtbarkeit von Entitätenmengen durch die SetEntitySetAccessRule-Methode gesteuert wird. Die folgende Codezeile in der Datendienstdefinition ermöglicht z. B. den Zugriff auf den CustomersByCity-Dienstvorgang.
config.SetServiceOperationAccessRule( _
"GetOrdersByCity", ServiceOperationRights.AllRead)
config.SetServiceOperationAccessRule(
"GetOrdersByCity", ServiceOperationRights.AllRead);
Hinweis
Wenn ein Dienstvorgang einen Rückgabetyp aufweist, der durch das Beschränken des Zugriff auf die zugrunde liegenden Entitätenmengen ausgeblendet wurde, dann steht der Dienstvorgang Clientanwendungen nicht zur Verfügung.
Weitere Informationen finden Sie unter Gewusst wie: Definieren eines Dienstvorgangs (WCF Data Services).
Auslösen von Ausnahmen
Es empfiehlt sich, dass Sie die DataServiceException-Klasse immer dann verwenden, wenn Sie eine Ausnahme in der Datendienstausführung auslösen. Das liegt daran, dass die Datendienstlaufzeit weiß, wie der HTTP-Antwort-Nachricht Eigenschaften dieses Ausnahmeobjekts ordnungsgemäß zugeordnet werden. Wenn Sie in einem Dienstvorgang eine DataServiceException auslösen, wird die zurückgegebene Ausnahme in eine TargetInvocationException eingeschlossen. Um die Basis-DataServiceException ohne die einschließende TargetInvocationException zurückzugeben, müssen Sie die HandleException(HandleExceptionArgs)-Methode im DataService<T> überschreiben und die DataServiceException aus der TargetInvocationException extrahieren und als Fehler der obersten Ebene zurückgeben, wie im folgenden Beispiel:
' Override to manage returned exceptions.
Protected Overrides Sub HandleException(args As HandleExceptionArgs)
' Handle exceptions raised in service operations.
If args.Exception.GetType() = GetType(TargetInvocationException) _
AndAlso args.Exception.InnerException IsNot Nothing Then
If args.Exception.InnerException.GetType() = GetType(DataServiceException) Then
' Unpack the DataServiceException.
args.Exception = _
TryCast(args.Exception.InnerException, DataServiceException)
Else
' Return a new DataServiceException as "400: bad request."
args.Exception = _
New DataServiceException(400, args.Exception.InnerException.Message)
End If
End If
End Sub
// Override to manage returned exceptions.
protected override void HandleException(HandleExceptionArgs args)
{
// Handle exceptions raised in service operations.
if (args.Exception.GetType() ==
typeof(TargetInvocationException)
&& args.Exception.InnerException != null)
{
if (args.Exception.InnerException.GetType()
== typeof(DataServiceException))
{
// Unpack the DataServiceException.
args.Exception = args.Exception.InnerException as DataServiceException;
}
else
{
// Return a new DataServiceException as "400: bad request."
args.Exception =
new DataServiceException(400,
args.Exception.InnerException.Message);
}
}
}