| 

.NET C# Java Javascript Exception

3
Hallo zusammen,

folgende Ausgangssituation:
In einer Portable Class Library befindet sich ein Interface mit folgender Methode:
DTO.Auto GetAutoById(int id)


Dieses Interface wird nun in einer anderen Assembly mit Hilfe von NHibernate implementiert, ca. so:
public DTO.Auto GetAutoById(int id)
{
Domain.Auto a = context.CreateCriteria(...)
return convertDomainToDTO(a);
}


Nun gibt es einen Webservice, der ebenfalls anhand einer Id ein DTO.Auto-Objekt zurückliefern kann. Wenn ich nun ein neues Projekt erstelle (ebenfall eine Portable Class Library) und dort die Webservice-Referenz einbinde, dann steht mir in der Webservice-Proxy-Klasse ausschließlich die GetAutoByIdAsync-Methode sowie das GetAutoByIdCompleted-Event zur Verfügung.

Wie kann ich nun mit Hilfe des Webservice-Proxy am besten das oben beschriebende Interface implementieren? Die Herausforderung besteht ja darin, den asynchronen Webservice-Aufruf und das Warten auf das Ergebnis nach außen hin (also aus Sicht des Interface-Client) zu verstecken.

public DTO.Auto GetAutoById(int id)
{
webserviceProxy.GetAutoByIdAsync(id);
?
return auto;
}
News:
14.09.2013
MoritzM 21 2
3 Antworten
0
Kannst Du nicht anstatt der event-basierten asynchronen Methoden die Task-basierten verwenden. Dann hast Du statt einem Pärchen aus GetXYZAsync und GetXYZCompleted eine Methode GetXYZAsync, die eine Task zurückliefert. Das programmiert sich um Welten bequemer.

Das sollte beim Erzeugen des Proxy via "Add Service Reference" eigentlich angeboten werden (abh. von VS-Version). Dann löst sich Dein Problem fast schon von selbst:

public DTO.Auto GetAutoById(int id)
{
// TODO: Exception handling
var task = webserviceProxy.GetAutoByIdAsync(id);

return task.Result; // blockiert, bis Result vorliegt
}


Damit blockiert halt der Aufrufer. Wenn Du das verhindern willst, musst Du je nach verfügbaren Mitteln noch ein wenig weiter ausholen, z.B. Task an den Client weiterreichen oder async/await nutzen...
15.09.2013
ffordermaier 8,4k 3 9
0
Hi!

Vielen Dank für deine Antwort. An deinen Vorschlag habe ich auch schon gedacht, Problem ist aber, dass ich über "Add Service Reference" -> "Advanced" keine Möglichkeit habe, auf Task-basierte Operationen umzustellen. Das Auswahlmenu ist deaktiviert, die Standardeinstellung ist "Asynchronous operations".
Versuche ich das ganze in einer Standard-.NET-Library, also eben keine Portable Class Library, kann kann ich sehr wohl auf Task-basierte Operationen umschalten.
Bin mir nicht sicher, ob das ganze ein Bug ist oder in Portable Class Libraries so beabsichtigt ist?!?

EDIT:
Folgende Links haben mir jetzt weitergeholfen:
http://www.codeproject.com/Articles/613678/Task-based-Asynchronous-Operation-in-WCF?msg=4611575#xx4611575xx

http://connect.microsoft.com/VisualStudio/feedback/details/771337/portable-class-library-add-service-reference-dialog

http://www.scottlogic.com/blog/2012/11/07/async-where-can-i-use-it.html

Besonders interessant finde ich den Artikel aus dem ersten Link. Würdet ihr das auch wie der Autor als state of the art bezeichnen?
15.09.2013
MoritzM 21 2
Welche Zielplattformen hast Du in der PCL gewählt?
ffordermaier 15.09.2013
.NET 4.5, Windows Phone 8, .NET for Windows Store Apps
MoritzM 15.09.2013
Ok, schön, dass Du es geschafft hast. Wie hat es denn jetzt geklappt, dass der Menüpunkt aktiviert war?

Der verlinkte CodeProject Artikel verwendet async/await (das ich auch schon angesprochen hatte). Das ist state-of-the-art, aber es entspricht nicht einem blockierendem synchronen Aufruf, den Deine Signatur "public DTO.Auto GetAutoById(int id)" hätte implementieren müssen.
ffordermaier 15.09.2013
Der Menupunkt lässt sich leider nicht aktivieren. Laut Bugreport wird Microsoft da auch erstmal nix machen. Habe die Proxyklasse selber implementiert:
[code]public class WebserviceClient : ClientBase<DTO.IAuftragRepository>, DTO.IAuftragRepository
{[/code] und dann die Methode: [code]public DTO.AuftragDTO GetAuftragByNummer(string auftragsnummer)
{
return this.Channel.GetAuftragByNummer(auftragsnummer);
}[/code]
MoritzM 17.09.2013
0
Zum Abschluss (nach Umstellung der Schnittstelle auf Task-basierte Operationen) noch mal der "vollständige" Lösungsansatz (hilfreich waren dabei http://www.guruumeditation.net/awaitable-wcf-calls-with-taskcompletionsource und http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj684580%28v=vs.105%29.aspx):

WCF-Client-Wrapper:
public Task<DTO.AuftragDTO> GetAuftragByNummer(string auftragsnummer)
{
var tcs = new TaskCompletionSource<DTO.AuftragDTO>();

this.wcfClient.GetAuftragByNummerCompleted += (o, args) =>
{
if (args.Error != null)
{
tcs.TrySetException(args.Error);
return;
}
if (args.Cancelled)
{
tcs.TrySetCanceled();
return;
}

tcs.TrySetResult(args.Result);
};

this.wcfClient.GetAuftragByNummerAsync("08-011");

return tcs.Task;
}


Aufruf z.B. aus ViewModel:
public async void SucheAuftragAsync()
{
DTO.AuftragDTO auftrag = await this.auftragRepository.GetAuftragByNummer("08-011");
this.Auftrag = new AuftragViewModel(auftrag);
}
23.09.2013
MoritzM 21 2

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH