Windows Phone 7 で WCF を使用すると System.UnsupportedException が発生する
-
21-09-2019 - |
質問
Windows Phone Series 7 エミュレーターで WCF を使用して通信できた人はいますか?
ここ2日間努力してきましたが、まさにそれが私に起こっています。通常の Silverlight コントロールは Silverlight 3 と Silverlight 4 の両方で動作しますが、電話版では動作しません。私が試した 2 つのバージョンは次のとおりです。
バージョン 1 - 非同期パターンの使用
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress("http://localhost/wcf/Authentication.svc");
Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress);
AsyncCallback callback = (result) =>
{
Action<string> write = (str) =>
{
this.Dispatcher.BeginInvoke(delegate
{
//Display something
});
};
try
{
Wcf.IAuthentication auth = result.AsyncState as Wcf.IAuthentication;
Wcf.AuthenticationResponse response = auth.EndLogin(result);
write(response.Success.ToString());
}
catch (Exception ex)
{
write(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.Message);
}
};
auth1.BeginLogin("user0", "test0", callback, auth1);
このバージョンは次の行で改行されます。
Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress);
投げ System.NotSupportedException
. 。例外はあまり説明的ではなく、コールスタックも同様にあまり役に立ちません。
System.servicemodel.diagnosticutility.exceptionutility.buildmessage(例外x)System.servicemodel.diagnosticutility.exceptututility.logexcection(例外x)at System.servicemodel.diagnosticutility.exceptutility.throwhereror .createChannel(endpointAddressアドレス)windowsphoneapplication2.mainpage.dologin()。
バージョン 2 - WCF 呼び出しのブロック
こちらは非同期パターンを使用しないバージョンです。
[System.ServiceModel.ServiceContract]
public interface IAuthentication
{
[System.ServiceModel.OperationContract]
AuthenticationResponse Login(string user, string password);
}
public class WcfClientBase<TChannel> : System.ServiceModel.ClientBase<TChannel> where TChannel : class {
public WcfClientBase(string name, bool streaming)
: base(GetBinding(streaming), GetEndpoint(name)) {
ClientCredentials.UserName.UserName = WcfConfig.UserName;
ClientCredentials.UserName.Password = WcfConfig.Password;
}
public WcfClientBase(string name) : this(name, false) {}
private static System.ServiceModel.Channels.Binding GetBinding(bool streaming) {
System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding();
binding.MaxReceivedMessageSize = 1073741824;
if(streaming) {
//binding.TransferMode = System.ServiceModel.TransferMode.Streamed;
}
/*if(XXXURLXXX.StartsWith("https")) {
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
}*/
return binding;
}
private static System.ServiceModel.EndpointAddress GetEndpoint(string name) {
return new System.ServiceModel.EndpointAddress(WcfConfig.Endpoint + name + ".svc");
}
protected override TChannel CreateChannel()
{
throw new System.NotImplementedException();
}
}
auth.Login("test0", "password0");
このバージョンはクラッシュします System.ServiceModel.ClientBase<TChannel>
コンストラクタ。呼び出しスタックは少し異なります。
System.REFLECTION.METHODINFO.GET_RETURNPARAMETER()at System.ServiceModel.Description.ServicereFlector.HasnodisposableParameters at System.ServiceModel.Description.Description.TypeloAder.CreatereTerationDescripation(ContractDessiptripcipripion)は、Methotedestiprefcripcipripion(Methotedessiptioniptiprefcription) LectionInfo ReflectionInfo、ContractDescription宣言契約) at System.ServiceModel.Description.TypeLoader.CreateOperationDescriptions(ContractDescription contractDescription, ContractReflectionInfo reflectionInfo, Type contractToGetMethodsFrom, ContractDescription declaringContract, MessageDirection direction) at System.ServiceModel.Description.TypeLoader.CreateContractDescription(ServiceContractAttribute contractAttr, Type contractType, Type serviceType, ContractReflectionInfo& reflectionInfo, Object serviceImplementation) at System.ServiceModel.Description.TypeLoader.LoadContractDescriptionHelper(Type contractType, Type serviceType, Object serviceImplementation) at System.ServiceModel.Description.TypeLoader.LoadContractDescription(Type contractType) at System.ServiceModel.ChannelFactory1.CreateDescription() at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address) at System.ServiceModel.ChannelFactory
1..CTOR(結合結合、EndPointAddress RemoteAddress)at System.ServicEmodel.ClientBase1..ctor(Binding binding, EndpointAddress remoteAddress) at Wcf.WcfClientBase
1..ctor(String名、ブールストリーミング)wcf.wcfclientbase`1..ctor(string name)at wcf.authenticationclient..ctor()atwondyphoneapplication2.mainpage.dologin()...
何か案は?
解決
scottmarlowe 氏が指摘したように、自動的に生成されたサービス参照はそのまま機能します。私は、なぜこれが機能し、マニュアル版が機能しないのかを解明するという使命を帯びました。
犯人を見つけました、そしてそれは ChannelFactory
. 。何らかの理由で new ChannelFactory<T>().CreateChannel()
例外をスローするだけです。私が見つけた唯一の解決策は、独自のチャネル実装を提供することです。これには以下が含まれます。
- ClientBase をオーバーライドします。(オプション)。
- ClientBase.CreateChannel をオーバーライドします。(オプション)。
- WCF インターフェイスの特定の実装を使用して ChannelBase をサブクラス化します。
現在、ClientBase はすでにチャネル ファクトリのインスタンスを提供しています。 ChannelFactory
財産。ただ電話するだけなら CreateChannel
そうしないと、同じ例外が発生します。ステップ 3 で定義したチャネルを内部からインスタンス化する必要があります。 CreateChannel
.
これは、すべてがどのようにまとめられているかを示す基本的なワイヤーフレームです。
[DataContractAttribute]
public partial class AuthenticationResponse {
[DataMemberAttribute]
public bool Success {
get; set;
}
[System.ServiceModel.ServiceContract]
public interface IAuthentication
{
[System.ServiceModel.OperationContract(AsyncPattern = true)]
IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object state);
AuthenticationResponse EndLogin(IAsyncResult result);
}
public class AuthenticationClient : ClientBase<IAuthentication>, IAuthentication {
public AuthenticationClient(System.ServiceModel.Channels.Binding b, EndpointAddress ea):base(b,ea)
{
}
public IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object asyncState)
{
return base.Channel.BeginLogin(user, password, callback, asyncState);
}
public AuthenticationResponse EndLogin(IAsyncResult result)
{
return Channel.EndLogin(result: result);
}
protected override IAuthentication CreateChannel()
{
return new AuthenticationChannel(this);
}
private class AuthenticationChannel : ChannelBase<IAuthentication>, IAuthentication
{
public AuthenticationChannel(System.ServiceModel.ClientBase<IAuthentication> client)
: base(client)
{
}
public System.IAsyncResult BeginLogin(string user, string password, System.AsyncCallback callback, object asyncState)
{
object[] _args = new object[2];
_args[0] = user;
_args[1] = password;
System.IAsyncResult _result = base.BeginInvoke("Login", _args, callback, asyncState);
return _result;
}
public AuthenticationResponse EndLogin(System.IAsyncResult result)
{
object[] _args = new object[0];
AuthenticationResponse _result = ((AuthenticationResponse)(base.EndInvoke("Login", _args, result)));
return _result;
}
}
}
TLDR; WP7 で独自の WCF コードを使用したい場合は、依存せずに独自のチャネル クラスを作成する必要があります。 ChannelFactory
.
他のヒント
ChannelFactory.CreateChannelを()を使用して、動的プロキシの作成は、Windows Phoneでサポートされていません。これは、ここに文書化されている - http://msdn.microsoft。 COM / EN-US /ライブラリ/ ff426930(VS.96).aspxのの
行うための正しい方法だろう非同期パターンで「追加サービス参照」メカニズムを使用してサービスを消費する。
私はこの非常にテーマに合わせてブログの記事を置く:<のhref = "http://blogs.msdn.com/b/andypennell/archive/2010/09/20/using-wcf-on-windows-phone -7-ウォークthrough.aspx」のrel = "nofollowをnoreferrer"> http://blogs.msdn.com/b/andypennell/archive/2010/09/20/using-wcf-on-windows-phone-7-ウォークthrough.aspxする
私は何の問題もありませんでしたが、私が行った「サービス参照を追加...」ルートB / C VS2010 RCがまだのためにその機能をサポートしていません。 WP7開発。 Expressバージョンが付属していますWP7開発者のインストールます。