Windows Phone 7에서 WCF를 사용한 System.UnsupportedException
-
21-09-2019 - |
문제
Windows Phone Series 7 에뮬레이터에서 WCF를 사용하여 통신 할 수있는 사람이 있습니까?
나는 지난 이틀 동안 노력해 왔고 그것은 단지 나를 위해 일어나고 있습니다. 나는 Silverlight 3과 Silverlight 4에서 작동하기 위해 일반적인 실버 라이트 컨트롤을 얻을 수 있지만 전화 버전은 아닙니다. 내가 시도한 두 가지 버전은 다음과 같습니다.
버전 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
. 예외는 그다지 설명이 아니며 Callstack은 그다지 도움이되지 않습니다.
system.servicemodel.diagnosticutility.xception ilfeance.servicemodel.diagnosticemodel.diagnosticutility.xceptionitility.logexception (예외 x)의 System.serviceModel.DiagnosticUtility.Exceptionitility.TiagnosticUtorror (예외) 1의 exceptoror (예외 x)의 System.servicemodel.diagnosticutility.exception. .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>
건설자. 통화 스택은 약간 다릅니다.
at System.Reflection.methodinfo.get_returnparameter ()에서 system.servicemodel.description.servicereflector.hasnodisposableparameters (methodinfo methodinfo)에서 system.servicemodel.description.typeloader.typeloader.cepleationporation (contracteportion) 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 system.servicemodel.description.typeloader.loadContractDescriptionHelper의 ServiceMementation) mentation) system.servicemodel.description.typeloader.loadContractDescription (system.servicemodel.channelfactory의 계약 유형)1.CreateDescription() at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address) at System.ServiceModel.ChannelFactory
1..ctor (System.servicemodel.clientbase의 결합 결합, EndpointAddress Remoteaddress)1..ctor(Binding binding, EndpointAddress remoteAddress) at Wcf.WcfClientBase
1..ctor (문자열 이름, 부울 스트리밍) wcf.wcfclientbase`1..ctor (문자열 이름) wcf.authenticationclient..ctor ()의 windowsphoneapplication2.mainpage.dologin () ...
어떤 아이디어?
해결책
Scottmarlowe가 지적했듯이 자동 생성 된 서비스 굴절은 작동합니다. 나는 그것이 작동하는 이유와 수동 버전이 그렇지 않은 이유를 해결하기 위해 미션을 시작했습니다.
나는 범인을 찾았다 ChannelFactory
. 몇 가지 이유 new ChannelFactory<T>().CreateChannel()
예외를 던졌습니다. 내가 찾은 유일한 해결책은 채널의 자신의 구현을 제공하는 것입니다. 여기에는 다음이 포함됩니다.
- 클라이언트베이스를 무시합니다. (선택 과목).
- ClientBase.CreateChannel을 재정의합니다. (선택 과목).
- WCF 인터페이스의 특정 구현을 갖춘 서브 클래스 채널베이스
이제 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/library/ff426930(vs.96).aspx
비동기 패턴으로 '서비스 참조 추가'메커니즘을 사용하여 서비스를 소비하는 것이 올바른 방법입니다.
이 주제에 대해 블로그 게시물을 모았습니다. http://blogs.msdn.com/b/andypennell/archive/2010/09/20/using-wcf-on-windows-7-walk-through.aspx
아무런 문제가 없었지만 Windows Phone 용 VS2010 Express를 통해해야 할 "서비스 참조 ..."경로를 사용했습니다. RC는 아직 WP7 개발 기능을 지원하지 않습니다. Express 버전은 WP7 개발자의 설치와 함께 제공됩니다.