WCF服务,但不在WPF中添加引用

时间:2016-06-17 05:17:06

标签: c# wpf wcf

我通过添加服务引用在WPF中创建了一个WCF消费应用程序。现在它工作正常。但是现在我有一个新的要求,即我想通过输入URL,用户名和密码来动态调用服务。

enter image description here

2 个答案:

答案 0 :(得分:1)

您可以在不使用ClientBase添加服务引用的情况下创建WCF客户端,但仍需要对接口的引用,以便编译器知道要调用的函数。

它的工作原理如下:

    public class ServiceClient : System.ServiceModel.ClientBase<IService>, IService {       
      public ServiceClient() {
      }

  public ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress) {
        }


      public void Login(string user, string password) {
            return base.Channel.Login(user, password);
      }
    }

    NetNamedPipeBinding binding = new NetNamedPipeBinding();
    binding.TransactionFlow = true;

    EndpointAddress address = new EndpointAddress(youraddress);

    ServiceClient client = new ServiceClient(binding, address);

    client.Login("xxx", "yyy");

答案 1 :(得分:0)

有关一般概念,请参阅this网站。创建一个新的VisualStudio解决方案并添加WCF服务应用程序项目和单元测试项目。将以下代码放在测试项目中(链接中稍微修改过的代码版本),并将缺少的引用添加到单元测试项目中。无需调试即可启动WCF服务,如果需要,可更改测试中的portnumber并运行测试。正如文章中提到的,代码在投入生产之前仍然可以使用一些调整。

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Xml.Linq;

namespace UnitTestProject1
{
    public class ServiceDetail
    {
        public Uri WSDLUri { get; set; }
        public Uri ServiceUri { get; set; }
        public String ContractName { get; set; }
        public string MethodName { get; set; }
    }

    public class GenericService
    {
        public object Call(ServiceDetail svc, List<object> payLoads)
        {
            //Import WSDL
            WsdlImporter imptr = ImportWSDL(svc.WSDLUri);
            //Extract Service and Data Contract Descriptions
            Collection<ContractDescription> svcCtrDesc = imptr.ImportAllContracts();
            //Compile the description to assembly
            var assembly = GetAssembly(svcCtrDesc);
            if (assembly == null) return null;
            //Extract all end points available on the WSDL
            IDictionary<string, IEnumerable<ServiceEndpoint>> allEP = GetEndPointsOfEachServiceContract(imptr, svcCtrDesc);
            IEnumerable<ServiceEndpoint> currentSvcEP;
            if (allEP.TryGetValue(svc.ContractName, out currentSvcEP))
            {
                //Find the endpoint of the service to which the proxy needs to contact
                var svcEP = currentSvcEP.First(x => x.ListenUri.AbsoluteUri == svc.ServiceUri.AbsoluteUri);
                //Generate proxy
                var proxy = GetProxy(svc.ContractName, svcEP, assembly);
                //Deserialize each payload argument to object
                List<object> pls = new List<object>();
                foreach (var pl in payLoads)
                {
                    object clrObj = null;
                    try
                    {
                        clrObj = Deserialize(pl.ToString(), assembly);
                    }
                    catch
                    {
                        clrObj = pl;
                    }
                    pls.Add(clrObj);
                }
                //Find opration contract on the proxy and invoke
                return proxy.GetType().GetMethod(svc.MethodName).Invoke(proxy, pls.ToArray());
            }
            return null;
        }

        private Assembly GetAssembly(Collection<ContractDescription> svcCtrDesc)
        {
            CodeCompileUnit ccu = GetServiceAndDataContractCompileUnitFromWSDL(svcCtrDesc);
            CompilerResults rslt = GenerateContractsAssemblyInMemory(new CodeCompileUnit[] { ccu });
            if (!rslt.Errors.HasErrors)
                return rslt.CompiledAssembly;
            return null;
        }
        private object GetProxy(string ctrName, ServiceEndpoint svcEP, Assembly assembly)
        {
            Type prxyT = assembly.GetTypes().First(t => t.IsClass && t.GetInterface(ctrName) != null && t.GetInterface(typeof(ICommunicationObject).Name) != null);
            object proxy = assembly.CreateInstance(prxyT.Name, false, System.Reflection.BindingFlags.CreateInstance,
                                    null, new object[] { svcEP.Binding, svcEP.Address }, CultureInfo.CurrentCulture, null);
            return proxy;
        }
        private WsdlImporter ImportWSDL(Uri wsdlLoc)
        {
            MetadataExchangeClient mexC = new MetadataExchangeClient(wsdlLoc, MetadataExchangeClientMode.HttpGet);
            mexC.ResolveMetadataReferences = true;
            MetadataSet metaSet = mexC.GetMetadata();
            return new WsdlImporter(metaSet);
        }
        private Dictionary<string, IEnumerable<ServiceEndpoint>> GetEndPointsOfEachServiceContract(WsdlImporter imptr, Collection<ContractDescription> svcCtrDescs)
        {
            ServiceEndpointCollection allEP = imptr.ImportAllEndpoints();
            var ctrEP = new Dictionary<string, IEnumerable<ServiceEndpoint>>();
            foreach (ContractDescription svcCtrDesc in svcCtrDescs)
            {
                List<ServiceEndpoint> eps = allEP.Where(x => x.Contract.Name == svcCtrDesc.Name).ToList();
                ctrEP.Add(svcCtrDesc.Name, eps);
            }
            return ctrEP;
        }
        private CodeCompileUnit GetServiceAndDataContractCompileUnitFromWSDL(Collection<ContractDescription> svcCtrDescs)
        {
            ServiceContractGenerator svcCtrGen = new ServiceContractGenerator();
            foreach (ContractDescription ctrDesc in svcCtrDescs)
            {
                svcCtrGen.GenerateServiceContractType(ctrDesc);
            }
            return svcCtrGen.TargetCompileUnit;
        }
        private object Deserialize(string xml, Assembly assembly)
        {
            Type ctr = GetDataContractType(xml, assembly);
            return Deserialize(xml, ctr);
        }
        private object Deserialize(string xml, Type toType)
        {
            using (Stream stream = new MemoryStream())
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
                stream.Write(data, 0, data.Length);
                stream.Position = 0;
                DataContractSerializer d = new DataContractSerializer(toType);
                return d.ReadObject(stream);
            }
        }
        private Type GetDataContractType(string xml, Assembly assembly)
        {
            var serializedXML = ConvertToXML(xml);
            var match = assembly.GetTypes().First(x => x.Name == serializedXML.Root.Name.LocalName);
            return match;
        }
        private XDocument ConvertToXML(string xml)
        {
            using (Stream stream = new MemoryStream())
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
                stream.Write(data, 0, data.Length);
                stream.Position = 0;
                return XDocument.Load(stream);
            }
        }
        private CompilerResults GenerateContractsAssemblyInMemory(params CodeCompileUnit[] codeCompileUnits)
        {
            // Generate a code file for the contracts 
            CodeGeneratorOptions opts = new CodeGeneratorOptions();
            opts.BracingStyle = "C";
            CodeDomProvider pro = CodeDomProvider.CreateProvider("C#");
            // Compile the code file to an in-memory assembly
            // Don't forget to add all WCF-related assemblies as references
            CompilerParameters prms = new CompilerParameters(new string[] { "System.dll", "System.ServiceModel.dll",
                "System.Runtime.Serialization.dll"});
            prms.GenerateInMemory = true;
            prms.GenerateExecutable = false;
            return pro.CompileAssemblyFromDom(prms, codeCompileUnits);
        }
    }

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            // Arrange         
            var target = new GenericService();
            var serviceDetail = new ServiceDetail
            {
                WSDLUri = new Uri("http://localhost:13152/Service1.svc?singleWsdl"),
                ServiceUri = new Uri("http://localhost:13152/Service1.svc"),
                ContractName = "IService1",
                MethodName = "GetData"
            };
            var arguments = new List<object> { 5 };

            // Act
            var result = target.Call(serviceDetail, arguments);

            // Assert
            Assert.AreEqual("You entered: 5", result);

        }
    }
}