Silverlight WCF 封装尝试

   研究silverlight wcf陆陆续续有一段时间了,由于一直不太适应传统的引用做法,所以想封装出一个简单的方法进行silverlight 和wcf之间通讯。

大家都知道,如果是控制台程序或者是winform程序,在程序中要发布一个wcf很简单,可以开辟一个线程,在登录或者主窗口初始化的时候把服务开启即可,

但是对于silverlight比较特殊,程序已启动,就直接加载SL客户端,在启动的时候,在服务端要做一些事情不太容易,而你等silverlight再想做服务端的事情时,

就没那么简单了,必须要用通讯。

  传统的wcf引用的方法是,在web目录新建一个wcf服务,会自动生成一个svc文件和一个对应的服务接口,右键svc文件,选择在浏览器中运行,然后再SL客户端

现在引用服务,弹出窗口中点发现,然后会自动生成一个客户端,和配置文件。然后再客户端使用的时候创建客户端实例,然后再调用同步方法和方法回调。这种方

法不易于维护和管理,工作起来也挺别扭。所以,我决定封装起来,尽量把这个通道简化一点。

下面是项目的结构

一:服务端Service

 有2个服务,每个服务分别一个接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace Service
{
    [ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        void DoWork();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Service
{
    public class TestService : ITestService
    {
        public void DoWork()
        {
            

        }
    }
}

 第二个接口和实现,返回字符串

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace Service
{
    [ServiceContract]
    public interface ITestService2
    {
        [OperationContract]
        string GetData(string str);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Service
{
    public class TestService : ITestService
    {
        public void DoWork()
        {
            

        }
    }
}

OK,服务端定义和实现就这些,

   然后看web项目怎么配置吧,首先先把服务类库引用过来,然后添加两个wcf,名称和服务实现类名一致,把自动生成的接口文件删除,以及.cs文件也删除,然后双击打开svc文件,改成如下配置。

如果没有需求,web层的工作到此就结束了。最后看客户端是怎么实现的,客户端有2个异步服务接口,其实,通用引用方式引用服务的时候,也会自动生成对应的接口,一个开始begin,和一个结束end,不过,我在这里给服务特性加了一个configname属性,用来匹配svc文件,所以ConfigurationName要等于你的svc文件名一致,看下面的代码吧。

using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ServiceModel;
namespace Service
{
    [ServiceContract(ConfigurationName = "TestService")]
    public partial interface ITestService
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginDoWork(AsyncCallback callback, object state);
        void EndDoWork(IAsyncResult result);
    }
}
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ServiceModel;
namespace Service
{
    [ServiceContract(ConfigurationName = "TestService2")]
    public partial interface ITestService2
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginGetData(string str, AsyncCallback callback, object state);
        string EndGetData(IAsyncResult result);
    }
}

 客户端定义就到此结束,最后还剩下一个使用wcf,留到最后讲,下面看代理类,客户端只要传递服务接口,就可以返回一个代理类实例,然后使用服务的开始方法和结束方法,

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Linq;
namespace Proxy
{
    public class Proxy
    {
        /// <summary>
        /// 根据接口创建一个wcf接口实例
        /// </summary>
        /// <typeparam name="T">服务接口</typeparam>
        /// <returns>接口实例</returns>
        public static T GetService<T>()
        {

            var xapUri = Application.Current.Host.Source;
            //web路径
            var webUri = new Uri(xapUri, "../");
            string webpath = webUri.ToString();
            Type type = typeof(T);
            //wcf服务全路径
            string url = "";

            //获取接口契约的特性
            object[] atbs = type.GetCustomAttributes(typeof(ServiceContractAttribute), false);
            if (atbs.Any(cp => cp.GetType() == typeof(ServiceContractAttribute)))
            {
                ServiceContractAttribute abt = atbs.First(cp => cp.GetType() == typeof(ServiceContractAttribute)) as ServiceContractAttribute;
                string servicepath = abt.ConfigurationName;
                url = webpath + servicepath;
            }

            //生成接口实例
            if (!string.IsNullOrEmpty(url))
            {
                EndpointAddress epAddress = new EndpointAddress(url + ".svc");
                Binding binding = new BasicHttpBinding();
                ChannelFactory<T> factory = new ChannelFactory<T>(binding, epAddress);
                T client = factory.CreateChannel();
                return client;
            }
            else
                return default(T);
        }
    }
}

 在客户端项目中,把这个代理类库引用进来,就可以使用了,使用代码如下

 private void button1_Click(object sender, RoutedEventArgs e)
        {
            ITestService client = Proxy.Proxy.GetService<ITestService>();
            client.BeginDoWork((result) =>
            {
                Deployment.Current.Dispatcher.BeginInvoke(() => { MessageBox.Show("第一个服务执行完毕"); });
            }, null);


            ITestService2 client2 = Proxy.Proxy.GetService<ITestService2>();
            client2.BeginGetData("123", (result) =>
            {
                Deployment.Current.Dispatcher.BeginInvoke(() => { MessageBox.Show(client2.EndGetData(result)); });
            }, null);
        }

 

到此,这个工作就结束了。

这样做的好处就是,你不需要面对一堆的配置文件,只需要定义接口和实现,也易于再次对接口的封装,使用起来也方便,只要对代理类传递接口就可以得到一个服务实例,不用关心服务如何配置,如何实现。总之,我觉得还挺适合我,不知道对各位有没有用,欢迎大家来讨论和拍砖!!! 最后感谢一些一个叫“飞”的网友,他帮我解决了一些谜团。

原文地址:https://www.cnblogs.com/Rmeo/p/3230560.html