【发布时间】:2011-10-13 00:46:03
【问题描述】:
原来是这样:
我正在尝试从 Windows 窗体客户端应用程序中调用 WCF 服务的方法。我没有合同类定义。我唯一拥有的是服务的 URI,即http://ip:port/Service1.svc。
所以我想我可以为此创建一个代理类。我想在运行时创建代理类,所以任何用于创建代理类和导入到项目的外部工具都帮不了我。
我设法在运行中创建了代理类。代码如下:
Dim mexClient As MetadataExchangeClient = New MetadataExchangeClient(New Uri(webServicesWSDLUrl), MetadataExchangeClientMode.HttpGet)
mexClient.ResolveMetadataReferences = True
Dim metaDocs As MetadataSet = mexClient.GetMetadata()
Dim importer As WsdlImporter = New WsdlImporter(metaDocs)
Dim generator As ServiceContractGenerator = New ServiceContractGenerator()
Dim dataContractImporter As New Object
Dim xsdDCImporter As XsdDataContractImporter
If (Not importer.State.TryGetValue(GetType(XsdDataContractImporter), dataContractImporter)) Then
Console.WriteLine("Couldn't find the XsdDataContractImporter! Adding custom importer.")
xsdDCImporter = New XsdDataContractImporter()
xsdDCImporter.Options = New ImportOptions()
importer.State.Add(GetType(XsdDataContractImporter), xsdDCImporter)
Else
xsdDCImporter = TryCast(dataContractImporter, XsdDataContractImporter)
If (xsdDCImporter.Options Is Nothing) Then
Console.WriteLine("There were no ImportOptions on the importer.")
xsdDCImporter.Options = New ImportOptions()
End If
End If
Dim exts As System.Collections.IEnumerable = importer.WsdlImportExtensions
Dim newExts As New System.Collections.Generic.List(Of IWsdlImportExtension)
For Each ext As IWsdlImportExtension In exts
Console.WriteLine("Default WSDL import extensions: {0}", ext.GetType().Name)
newExts.Add(ext)
Next
Dim polExts As System.Collections.IEnumerable = importer.PolicyImportExtensions
importer = New WsdlImporter(metaDocs, polExts, newExts)
Dim Contracts As System.Collections.ObjectModel.Collection(Of ContractDescription) = importer.ImportAllContracts()
importer.ImportAllEndpoints()
importer.ImportAllBindings()
For Each contract As ContractDescription In Contracts
generator.GenerateServiceContractType(contract)
Next
If generator.Errors.Count <> 0 Then
Throw New Exception("There were errors during code compilation.")
End If
Dim nmspace As CodeNamespace = New CodeNamespace()
Dim unit1 As CodeCompileUnit = New CodeCompileUnit()
unit1.Namespaces.Add(nmspace)
Dim CodeDomProvider As System.CodeDom.Compiler.CodeDomProvider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("VB")
Dim assemblyReferences() As String
assemblyReferences = New String() {"System.dll", _
"System.Web.Services.dll", "System.Web.dll", _
"System.Xml.dll", "System.Data.dll"}
Dim parms As CompilerParameters = New CompilerParameters(assemblyReferences)
parms.GenerateInMemory = True '(Thanks for this line nikolas)
'CompilerRsults
results = CodeDomProvider.CompileAssemblyFromDom(parms, generator.TargetCompileUnit)
现在使用results 创建我的WebService 实例(methodName = "GetData",args = new Object() { 4 }):见下文..
Dim wsvcClass As Object = results.CompiledAssembly.CreateInstance(serviceName)
Dim retValue As Object = wsvcClass.GetType().InvokeMember(methodName, BindingFlags.InvokeMethod, Nothing, wsvcClass, args)
最后一条命令抛出异常
A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at http://ip:port/Service1.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. ---> System.Net.WebException: The remote server returned an error: (404) Not Found.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
--- End of inner exception stack trace ---
Server stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.ReA first chance exception of type 'System.NullReferenceException' occurred in ThirdPartyAPIClientApp.exe
questChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at IService1.GetData(Int32 value)
at Service1Client.GetData(Int32 value)
您可以在下面找到Web Service的web.config和客户端应用程序的App.config
web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
</system.web>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messages"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\logs\messages.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="false"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="false"
maxMessagesToLog="3000"
maxSizeOfMessageToLog="2000"/>
</diagnostics>
<services>
<!-- Note: the service name must match the configuration name for the service implementation. -->
<service name="WcfService1.Service1" behaviorConfiguration="BasicHttpBinding_This" >
<endpoint address="/Service1.svc" contract="WcfService1.IService1" binding="basicHttpBinding" bindingNamespace="http://ip:port/WCF1_Test" />
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="BasicHttpBinding_This">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_This" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="200000000000000" maxReceivedMessageSize="200000000000000"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
App.config
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_This" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="200000000" maxReceivedMessageSize="200000000"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="200000000"
maxArrayLength="200000000" maxBytesPerRead="200000000" maxNameTableCharCount="200000000" />
<security mode="None">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://ip:port/Service1.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_This"
contract="IService1" name="BasicHttpBinding_This" />
</client>
</system.serviceModel>
</configuration>
另外我正在发送合同和WebService的代码类
合同
<ServiceContract(Namespace:="http://ip:port/WCF1_Test")>
Public Interface IService1
<OperationContract(isOneway:=False)>
Function GetData(ByVal value As Integer) As String
<OperationContract(isOneway:=False)>
Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType
' TODO: Add your service operations here
End Interface
' Use a data contract as illustrated in the sample below to add composite types to service operations.
<DataContract()>
Public Class CompositeType
<DataMember()>
Public Property BoolValue() As Boolean
<DataMember()>
Public Property StringValue() As String
End Class
代码类
<ServiceBehavior(Namespace:="http://ip:port/WCF1_Test")>
Public Class Service1
Implements IService1
Public Sub New()
End Sub
Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData
Return String.Format("You entered: {0}", value)
End Function
Public Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType Implements IService1.GetDataUsingDataContract
If composite Is Nothing Then
Throw New ArgumentNullException("composite")
End If
If composite.BoolValue Then
composite.StringValue &= "Suffix"
End If
Return composite
End Function
End Class
有人知道解决办法吗?如果有人只知道 URI,那么动态调用 WCF 方法的正确方法是什么? PS:Web 服务已在 IIS7 上启动并运行
【问题讨论】:
-
有一个关于代码项目的完整教程 - 动态生成 WCF 代理。这似乎涵盖了您想要做的事情:
-
谢谢 Preet.. 但在一般解决方案中,我无法访问所引用的 Web 服务......只有它的 URI,正如我所提到的......
-
@Ermis:那你怎么知道如何调用它,作为参数传入什么数据,期望返回什么数据,它使用什么绑定,安全要求是什么等等?请更详细地说明您的方案和需求。
-
Allon 我想建立一种机制来自动将客户端的 Web 服务注册到我的系统,以便我能够调用任何我想要的具有该方法名称的方法。 (可以说这些方法是 Subs 并且不带参数)。我目前正在尝试使用 BasicHttpBinding,此时我并不关心安全性。
标签: wcf class proxy dynamic invoke