Bug 51959 - Async WCF message construction uses wrong name
Summary: Async WCF message construction uses wrong name
Status: CONFIRMED
Alias: None
Product: Class Libraries
Classification: Mono
Component: WCF assemblies (show other bugs)
Version: 4.6.0 (C8)
Hardware: PC Windows
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2017-01-30 15:12 UTC by github
Modified: 2018-02-02 01:04 UTC (History)
6 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description github 2017-01-30 15:12:54 UTC
Overview
========

I'm trying to create a .Net Standard 1.3 library which wraps a WCF service for cross-platform usage. I use Visual Studio's "Create Service Reference" in a .Net Framework project to auto-generate the bulk of the code, and then reference that auto-generated code from the .Net Standard library and wrap it in a layer which manages ChannelFactory and Channel instances.

The auto-generated code supports synchronous and task-based asynchronous invocation. When I call the synchronous versions of the methods from Android they work, but when I call the asynchronous methods I get errors indicating that the generated SOAP message included "Async" in the name incorrectly.

The problem is observed with Xamarin.Android 7.0.2.42.


Reproduction
============

Because this is quite complicated I've put the minimal reproducible test case on GitHub at https://github.com/pjt33/PortableWCFSandbox . The solution contains four projects:

1. DemoService.WCF is the service. I've deployed it to Azure as https://demoservicewcf.azurewebsites.net/DemoService.svc and include the code in the GitHub project solely for completeness. This service has one remote method, `Reverse`, which reverses a string.
2. FrameworkClient is a .Net console project which has an auto-generated service reference and calls `Reverse` both synchronously and asynchronously.
3. NetStandardClientLib is a .Net Standard 1.3 project which uses FrameworkClient's auto-generated reference code and wraps it in a simple proxy. It has a NuGet reference to System.ServiceModel.Http.
4. AndroidClientIndirect is a Xamarin Android project which references NetStandardClientLib. It also calls `Reverse` both synchronously and asynchronously.


Expected results
================
Both FrameworkClient and AndroidClientIndirect should be able to make synchronous and asynchronous calls.

Alternatively, if asynchronous calls are not supported then an error message should be thrown which clearly states that asynchronous calls are not supported.


Actual results
==============
FrameworkClient successfully makes synchronous and asynchronous calls. AndroidClientIndirect successfully makes synchronous calls, but the asynchronous call throws

System.AggregateException: One or more errors occurred. ---> System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: Error in deserializing body of request message for operation 'Reverse'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'Reverse' and namespace 'urn:fdc:cheddarmonk.org:2017:Demo'. Found node type 'Element' with name 'ReverseAsync' and namespace 'urn:fdc:cheddarmonk.org:2017:Demo'
  at (wrapper managed-to-native) System.Object:__icall_wrapper_mono_remoting_wrapper (intptr,intptr)
  at (wrapper remoting-invoke) FrameworkClient.Bar.IDemoService:ReverseAsync (string)
  at NetStandardClientLib.DemoServiceProxy+<ReverseAsync>d__3.MoveNext () [0x0002e] in C:\Users\pjt33\Documents\Visual Studio 2015\Projects\PortableWCFSandbox\NetStandardClientLib\DemoServiceProxy.cs:51 
   --- End of inner exception stack trace ---
  at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00014] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2157 
  at System.Threading.Tasks.Task`1[TResult].GetResultCore (System.Boolean waitCompletionNotification) [0x00034] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:562 
  at System.Threading.Tasks.Task`1[TResult].get_Result () [0x00000] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:532 
  at AndroidClientIndirect.MainActivity.OnCreate (Android.OS.Bundle bundle) [0x0006e] in C:\Users\pjt33\Documents\Visual Studio 2015\Projects\PortableWCFSandbox\AndroidClientIndirect\MainActivity.cs:28
Comment 2 Brendan Zagaeski (Xamarin Team, assistant) 2017-12-14 05:07:50 UTC
Based on the bug reporter's comment on another bug (Bug 13074, Comment 2), it sounds like adding support to handle Task-based asynchronous WCF proxy methods might involve a bit more than correcting the method name in the SOAP message.  I'll plan to experiment a little bit with that when I get chance, if no one beats me to it.

For now, I'll add some notes on a slightly different topic because there have been some changes in the new project experience in the latest Visual Studio 2017 version 15.5 that are relevant to this bug.




## Changes in the new project experience in Visual Studio 2017 version 15.5


- There is a change (apparently undocumented [1][2], but probably intentional) in Visual Studio 2017 version 15.5 that removes the Portable Class Library template project from the new project dialog.

[1] https://www.visualstudio.com/news/releasenotes/vs2017-relnotes
[2] https://developercommunity.visualstudio.com/content/problem/166688/portable-class-library-pcl-missing-in-vs-2017-prof.html


- At the same time, starting in this version of Visual Studio, the .NET Standard project type now provides the new "WCF Web Service Reference connected service provider" [3] tool.  That tool _only_ generates Task-based asynchronous methods.  It generates neither synchronous methods [4] nor the old APM style (begin/end) asynchronous methods.

(As hinted at in Comment 0, before this latest Visual Studio 2017 release, the .NET Standard project type did not provide a direct way of adding WCF service references, so users would use other project types and copy over the generated proxies.)

[3] https://www.visualstudio.com/news/releasenotes/vs2017-relnotes#WCFTools
[4] https://github.com/dotnet/wcf/issues/654


- For comparison, in Visual Studio 2017 version 15.4, adding a WCF service reference to a PCL project generates a proxy that includes both synchronous methods and APM style (begin/end) asynchronous methods.




## Generating a proxy with synchronous and APM style asynchronous methods in Visual Studio 2017 version 15.5

In case any users come across this change in new project experience, note that it is still possible to generate the old WCF proxies that work with Xamarin:

Run `svcutil.exe` [5] on the command line in a developer command prompt to generate the proxy.  Include the `/async` flag on the command line if asynchronous methods are desired.

In my (admittedly very simple) tests with a template "Visual C# > WCF > WCF Service Application", the various synchronous and asynchronous methods in this kind of proxy all worked fine under in Mono, whether compiled directly into the main executable assembly or compiled into a .NET Standard library referenced by the main assembly.

[5] https://docs.microsoft.com/dotnet/framework/wcf/servicemodel-metadata-utility-tool-svcutil-exe
Comment 3 Brendan Zagaeski (Xamarin Team, assistant) 2017-12-14 19:09:07 UTC
> that removes the Portable Class Library template project from the new
> project dialog.
Correction: The template still exists, but it is not visible by default under the "Visual C#" node.  If you search for "class library portable" in the new project dialog search box, that project type can be found as:

> Class Library (Legacy Portable)
> 
> This project type has been deprecated. You should use Class Library
> (.NET Standard) instead.

After I created a project of this type, the item became visible by default once more under the "Visual C#" node in the new project dialog.
Comment 4 FieldstrikeMobile 2018-02-01 16:05:13 UTC
I am also seeing this issue.

I cannot use any WCF services I add to my .Net Standard 1.4 project.

Is there a workaround?
Comment 5 Brendan Zagaeski (Xamarin Team, assistant) 2018-02-02 01:04:40 UTC
## Partial workaround to generate just the synchronous and begin/end asynchronous methods

One approach is to generate the proxy from the command line using SvcUtil.exe with the `/async` and `/tcv:Version35` switches.  The full command would look similar to:

SvcUtil.exe /async /tcv:Version35 http://127.0.0.1/Service1.svc /out:Reference.cs

When targeting .NET Standard 1.4, you would need to hand-edit the resulting Reference.cs file to remove any occurrences of `IExtensibleDataObject` and any `ExtensionDataObject` properties or fields.  This is necessary because the `IExtensibleDataObject` is not available in .NET Standard 1.4 [1].  From what I could find, it looks like SvcUtil.exe doesn't have an easy automatic option to skip including those types in the proxy [2].

[1] https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.iextensibledataobject?view=netstandard-1.4
[2] https://stackoverflow.com/questions/22176608/is-there-a-way-to-prevent-svcutil-from-implementing-iextensibledataobject

.NET Standard 2.0 includes `IExtensibleDataObject` and `ExtensionDataObject`, so no hand-editing is needed for those types when targeting that version.




## Alternate partial workaround

Another option is to create a Portable Class Library project (as per Comment 3), use the old "Project > Add Service Reference..." menu command (rather than the new "Project > Add Connected Service" menu command), and then copy the generated Reference.cs proxy from the PCL into the .NET Standard project.  Generating the proxy this way automatically avoids the `IExtensibleDataObject` and `ExtensionDataObject` types.




## Stack Overflow cross-reference

https://stackoverflow.com/questions/47989563/how-to-use-wcf-services-in-netstandard-with-xamarin-forms-project/

Note You need to log in before you can comment on or make changes to this bug.