Silverlight跨域调用服务层的WCF Ria Service,但有个不完美的地方:Silverlight客户端添加WCF Ria Service的服务引用是死的,部署的时候怎么办?也就是WCF Ria Service的地址必须是可配置的,动态的。
本文给出解决方案。Silverlight客户端添加WCF Ria Service的服务引用后,会自动生成一个ServiceReferences.ClientConfig文件,内容大致如下:
- <configuration>
- <system.serviceModel>
- <bindings>
- <customBinding>
- <binding name="CustomBinding_SLEnalbedWcfService1">
- <binaryMessageEncoding />
- <httpTransport maxReceivedMessageSize="2147483647"
- maxBufferSize="2147483647" />
- </binding>
- </customBinding>
- </bindings>
- <client>
- <endpoint address="http://localhost:7236/SLEnalbedWcfService1.svc"
- binding="customBinding" bindingConfiguration=
- "CustomBinding_SLEnalbedWcfService1"
- contract="ServiceReference1.SLEnalbedWcfService1"
- name="CustomBinding_SLEnalbedWcfService1" />
- </client>
- </system.serviceModel>
- </configuration>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_SLEnalbedWcfService1">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:7354/SLEnalbedWcfService1.svc"
binding="customBinding" bindingConfiguration=
"CustomBinding_SLEnalbedWcfService1"
contract="ServiceReference1.SLEnalbedWcfService1"
name="CustomBinding_SLEnalbedWcfService1" />
</client>
</system.serviceModel>
</configuration>
里面就有写死的endpoint地址,如果我们要动态设置服务地址,这个文件必须要干掉。OK,首先在VS2010中删除这个文件,然后运行下,肯定报错,没关系,我们首先建立服务工具类:ServiceUtil.cs,代码如下:
- 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 SilverlightApplication1.ServiceReference1;
- using System.ServiceModel;
- namespace SilverlightApplication1
- {
- public class ServiceUtil
- {
- public static SLEnalbedWcfService1Client GetServiceClient()
- {
- BasicHttpBinding binding = new BasicHttpBinding(
- Application.Current.Host.Source.Scheme.Equals("https",
- StringComparison.InvariantCultureIgnoreCase)
- ? BasicHttpSecurityMode.Transport :
- BasicHttpSecurityMode.None);
- binding.MaxReceivedMessageSize = int.MaxValue;
- binding.MaxBufferSize = int.MaxValue;
- return new SLEnalbedWcfService1Client(binding, new EndpointAddress(
- new Uri("http://localhost:7326/SLEnalbedWcfService1.svc*这个地址可以从配置文件读取*/, UriKind.Absolute))); //cross domain
- "
- /
- //new Uri(Application.Current.Host.Source,
- "../SLEnalbedWcfService1.svc"))); //non-cross domain
- }
- }
- }
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 SilverlightApplication1.ServiceReference1;
using System.ServiceModel;
namespace SilverlightApplication1
{
public class ServiceUtil
{
public static SLEnalbedWcfService1Client GetServiceClient()
{
BasicHttpBinding binding = new BasicHttpBinding(
Application.Current.Host.Source.Scheme.Equals("https",
StringComparison.InvariantCultureIgnoreCase)
? BasicHttpSecurityMode.Transport :
BasicHttpSecurityMode.None);
binding.MaxReceivedMessageSize = int.MaxValue;
binding.MaxBufferSize = int.MaxValue;
return new SLEnalbedWcfService1Client(binding, new EndpointAddress(
new Uri("http://localhost:7326/SLEnalbedWcfService1.svc*这个地址可以从配置文件读取*/, UriKind.Absolute))); //cross domain
"
/
//new Uri(Application.Current.Host.Source,
"../SLEnalbedWcfService1.svc"))); //non-cross domain
}
}
}
然后用这个东东来实例化Service,代码:
- SLEnalbedWcfService1Client client =
- ServiceUtil.GetServiceClient();
SLEnalbedWcfService1Client client =
ServiceUtil.GetServiceClient();
运行一下,看看有没有错,如果有错,The remote server returned an error: NotFound. 看看原因在哪,然后看看是不是这个错误: The client and service bindings may be mismatched. 注意,跨域crossdomain.xml在服务端要有啊,或者clientaccesspolicy.xml也可以。
OK,如果你没有问题了,那就达到我们的目的了。注意:刚开始我们还是要添加web service引用的,否则得不到服务端WCF Ria Service接口类型,我们能动态配置的仅仅是服务端地址。(如果你WCF Ria Service的接口,svc名字等等都改了,那就要重新编译了。)
现在我们测试一下动态配置服务地址,假设我们的WCF Ria Service 移到另一个地址了。
如何模拟:在WCF Ria Service 的web application的项目属性里面的web属性页,修改一下port即可。
我们原来是自动分配的,7344端口,现在我们改为7355端口,svc地址也修改了。看看能不能动态调用WCF Ria Service呢。自己看看就ok了。
另:ServiceUtil类可以用generic(泛型)和反射 改良一下(老外原文):
- 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.Reflection;
- using System.ServiceModel;
- namespace SilverlightApplication1
- {
- /// <summary>
- /// sample:
- /// var client = ServiceUtil<serviceNamespace.SLEnalbedWcfService1Client>.GetInstance(ServiceType.Service1svc);
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public class ServiceUtil<T> where T : class
- {
- /// <summary>
- /// Service types
- /// </summary>
- public enum ServiceType
- {
- Service1svc
- }
- /// <summary>
- /// Create a service instance
- /// </summary>
- /// <param name="serviceType"></param>
- /// <returns></returns>
- public static T GetInstance(ServiceType serviceType)
- {
- T _instance = null;
- string serviceUri = GetServiceAddress(serviceType);
- if (string.IsNullOrEmpty(serviceUri)) return null;
- object[] paras = new object[2];
- BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
- binding.MaxBufferSize = int.MaxValue;
- binding.MaxReceivedMessageSize = int.MaxValue;
- EndpointAddress address = new EndpointAddress(new Uri(serviceUri, UriKind.Absolute));
- paras[0] = binding;
- paras[1] = address;
- ConstructorInfo constructor = null;
- try
- {
- Type[] types = new Type[2];
- types[0] = typeof(System.ServiceModel.Channels.Binding);
- types[1] = typeof(System.ServiceModel.EndpointAddress);
- constructor = typeof(T).GetConstructor(types);
- }
- catch (Exception)
- {
- return null;
- }
- if (constructor != null)
- _instance = (T)constructor.Invoke(paras);
- return _instance;
- }
- /// <summary>
- /// Get service address
- /// </summary>
- /// <param name="serviceType"></param>
- /// <returns></returns>
- public static string GetServiceAddress(ServiceType serviceType)
- {
- return "http://localhost:7354/SLEnalbedWcfService1.svc";//get from app.config is also ok
- }
- }
- }
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.Reflection;
using System.ServiceModel;
namespace SilverlightApplication1
{
/// <summary>
/// sample:
/// var client = ServiceUtil<serviceNamespace.SLEnalbedWcfService1Client>.GetInstance(ServiceType.Service1svc);
/// </summary>
/// <typeparam name="T"></typeparam>
public class ServiceUtil<T> where T : class
{
/// <summary>
/// Service types
/// </summary>
public enum ServiceType
{
Service1svc
}
/// <summary>
/// Create a service instance
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public static T GetInstance(ServiceType serviceType)
{
T _instance = null;
string serviceUri = GetServiceAddress(serviceType);
if (string.IsNullOrEmpty(serviceUri)) return null;
object[] paras = new object[2];
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
binding.MaxBufferSize = int.MaxValue;
binding.MaxReceivedMessageSize = int.MaxValue;
EndpointAddress address = new EndpointAddress(new Uri(serviceUri, UriKind.Absolute));
paras[0] = binding;
paras[1] = address;
ConstructorInfo constructor = null;
try
{
Type[] types = new Type[2];
types[0] = typeof(System.ServiceModel.Channels.Binding);
types[1] = typeof(System.ServiceModel.EndpointAddress);
constructor = typeof(T).GetConstructor(types);
}
catch (Exception)
{
return null;
}
if (constructor != null)
_instance = (T)constructor.Invoke(paras);
return _instance;
}
/// <summary>
/// Get service address
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public static string GetServiceAddress(ServiceType serviceType)
{
return "http://localhost:7354/SLEnalbedWcfService1.svc";//get from app.config is also ok
}
}
}
本文介绍了一种在Silverlight应用中实现跨域调用WCFRiaService的方法,通过自定义服务工具类实现服务地址的动态配置,避免了因硬编码服务地址带来的不便。
108

被折叠的 条评论
为什么被折叠?



