Ich frage mich, es ist möglich, benutzerdefinierte Nachricht Header zu ausgehenden Anfrage zu injizieren, um zusätzliche Informationen zu tragen, ohne die Payload deserialize die Funktionalität wie Authentifizierung, Validierung oder Korrelation der Anfrage wie wcf durch messagesinspector bereitgestellten erfüllt zu erfüllen?Wie fügt man der Anforderung einen Nachrichtenheader hinzu, wenn der Standardclient der Azure-Dienststruktur verwendet wird?
Antwort
aktualisieren
Mit SDK v2 können Sie jetzt (relativ) ändern leicht die Header sowohl zuverlässige Dienste und Schauspieler. Beachten Sie, dass in den folgenden Beispielen einige Wrapper-Elemente der Kürze halber weggelassen wurden.
Kunde
Wir verwenden ServiceProxyFactory
Proxies statt der statischen ServiceProxy
zu erstellen. Dann können wir IServiceRemotingClientFactory
und IServiceRemotingClient
wickeln und die Serviceaufrufe abfangen. Das Gleiche kann mit ActorProxyFactory
getan werden. Beachten Sie, dass dies das Verhalten von Attributen wie WcfServiceRemotingProviderAttribute
außer Kraft setzt, da wir die Client Factory explizit angeben.
_proxyFactory = new ServiceProxyFactory(c => new ServiceRemotingClientFactoryWrapper(
// we can use any factory here
new WcfServiceRemotingClientFactory(callbackClient: c)));
private class ServiceRemotingClientFactoryWrapper : IServiceRemotingClientFactory
{
private readonly IServiceRemotingClientFactory _inner;
public ServiceRemotingClientFactoryWrapper(IServiceRemotingClientFactory inner)
{
_inner = inner;
}
public async Task<IServiceRemotingClient> GetClientAsync(Uri serviceUri, ServicePartitionKey partitionKey, TargetReplicaSelector targetReplicaSelector,
string listenerName, OperationRetrySettings retrySettings, CancellationToken cancellationToken)
{
var client = await _inner.GetClientAsync(serviceUri, partitionKey, targetReplicaSelector, listenerName, retrySettings, cancellationToken).ConfigureAwait(false);
return new ServiceRemotingClientWrapper(client);
}
}
private class ServiceRemotingClientWrapper : IServiceRemotingClient
{
private readonly IServiceRemotingClient _inner;
public ServiceRemotingClientWrapper(IServiceRemotingClient inner)
{
_inner = inner;
}
public Task<byte[]> RequestResponseAsync(ServiceRemotingMessageHeaders messageHeaders, byte[] requestBody)
{
// use messageHeaders.AddHeader() here
return _inner.RequestResponseAsync(messageHeaders, requestBody);
}
public void SendOneWay(ServiceRemotingMessageHeaders messageHeaders, byte[] requestBody)
{
// use messageHeaders.AddHeader() here
_inner.SendOneWay(messageHeaders, requestBody);
}
}
Server
vererben ServiceRemotingDispatcher
und ActorServiceRemotingDispatcher
die Header zu untersuchen.
class CustomServiceRemotingDispatcher : ServiceRemotingDispatcher
{
public override async Task<byte[]> RequestResponseAsync(IServiceRemotingRequestContext requestContext, ServiceRemotingMessageHeaders messageHeaders, byte[] requestBody)
{
// read messageHeaders here
// or alternatively put them in an AsyncLocal<T> scope
// so they can be accessed down the call chain
return base.RequestResponseAsync(requestContext, messageHeaders, requestBody);
}
}
diese Klasse verwenden, wieder müssen wir die ServiceRemotingProviderAttribute
durch direkte Erstellung der Kommunikations Zuhörer außer Kraft zu setzen:
class MyService : StatelessService
{
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(context => new WcfServiceRemotingListener(context, new CustomServiceRemotingDispatcher());
}
}
Ich fragte the same question on the MSDN forum vor ein paar Wochen, aber ich bekam keine Antwort dort.
Ich schaute in den Quellcode der Client-Bibliothek und habe keine Möglichkeit gefunden, Header hinzuzufügen. Ich fürchte, der einzige Weg besteht darin, sie als Teil des Methodenaufrufs hinzuzufügen. Dies könnte erreicht werden, indem Anfrageklassen als Methodenparameter verwendet werden und Vererbung für sie verwendet wird. (z. B. RequestBase-Klasse mit Kopfzeilen [Authorization, ClientInfo, ...]). Sie müssen dann sicherstellen, dass diese Header für jede Anforderung festgelegt werden, indem alle Aufrufe umschlossen oder manuell festgelegt werden.
Eine weitere Klärung durch das Service Fabric-Team wäre sehr willkommen.
Wo id Sie den Client-Quellcode finden? Ich habe die API ausgecheckt, es gibt eine ServiceRemotingHeaders-Klasse, die mich glauben lässt, dass es Möglichkeiten gibt, der ausgehenden Anfrage einen eigenen Header hinzuzufügen. Außerdem scheint der Client die Kommunikation mit wcf durchzuführen. Sollte dies der Fall sein, sollte es möglich sein, den Nachrichteninspektor dem Entwickler zur Verfügung zu stellen. – Xiangdong
@Xiangdong Ich sah Microsoft.ServiceFabric.Services.dll mit ILSpy. ServiceRemotingHeaders scheint der richtige Weg zu sein, ja. Ich habe jedoch keinen Weg gefunden, sie von draußen zu setzen. Ich denke ServiceProxy.InvokeAsync() ist der Ort, der eine Anfrage initiiert und es erstellt die ServiceRemotingMessageHeaders-Variable intern und übergibt sie an den nachgelagerten ServicePartitionClient. Aber vielleicht habe ich etwas verpasst ... –
Ich gehe in die gleiche Richtung, dein Codebeispiel hilft definitiv sehr. Aber ich wünsche mir immer noch, Microsoft bietet den gleichen Nachrichten-Handler-Mechanismus, um solche Anwendungsfälle zu ermöglichen. – Xiangdong
Der ServiceInstanceListener hat keinen Konstruktorparameter für den Dispatcher auf die gleiche Weise wie der WcfServiceRemotingListener. Wie würde man bei Verwendung von Remoting einen Dispatcher hinzufügen? – SondreB
Problem ist, dass ServiceInstanceListener ICommunicationListener und nicht IServiceRemotingMessageHandler verwendet, und diese Schnittstelle hat keine Methoden, die Nachrichtenheader zurückgibt. – SondreB