开发者

Silverlight 3 WCF Multiple Servers

开发者 https://www.devze.com 2023-02-21 01:35 出处:网络
Please help...I\'m going crazy....I have a wcf service that exists on a few different servers.I need to dynamically change the endpoint address on my silverlight client depending on the environment it

Please help...I'm going crazy....I have a wcf service that exists on a few different servers. I need to dynamically change the endpoint address on my silverlight client depending on the environment its in. I'm currently getting a very detailed 404 error (sarcasm) when I try to change the address through code or by manually updating the client config file.

However, when I right-click on the service reference and go to configure service on my client I can change the address and it works.

I have the following service.

<system.serviceModel>
 <bindings>
  <basicHttpBinding>
    <binding name="DrawingServiceBasicHttp">
      <readerQuotas maxStringContentLength="2147483647" />
    </binding>
  </basicHttpBinding>
</bindings>

<service behaviorConfiguration="md" name="My.DrawingService">
    <endpoint address="Services" 
              binding="basicHttpBinding" 
              bindingConfiguration="DrawingServiceBasicHttp"
              name="DrawingServiceEndPoint" 
              contract="MyServices.IDrawingService" />
    <endpoint address="mex" 
              binding="mexHttpBinding" 
              bindingConfiguration=""
              name="DrawingMex" 
              contract="IMetadataExchange" />
 <behaviors>
  <serviceBehaviors>
    <behavior name="md">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="true"/>
    </behavior>
  </serviceBehaviors>
</behaviors>

My client config

<bindings>
        <basicHttpBinding>
            <binding name="DrawingServiceEndPoint" maxBufferSize="2147483647"
                maxReceivedMessageSize="2147483647">
                <security>
                    <transport>
                        <extendedProtectionPolicy policyEnforcement="Never" />
                    </transport>
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://MyHostName/Services/DrawingService.svc/Services"
            binding="basicHttpBinding" bindingConfiguration="DrawingServiceEndPoint"
            contract="EvalDrawingService.IDrawingService" name="DrawingServiceEndPoint" />
    </client>

In Code trying to set the address:

EvalDrawingService.DrawingServiceClient client = new EvalDrawingService.DrawingServiceClient("DrawingServiceEndPoint", GetServiceAddress());

I have verified the address being spit out by GetServiceAddress() is there and that I can use the browser to verify it exists (not to mention I can connect to it using the wcftestclient).

The Exception:

{System.ServiceModel.CommunicationException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound. at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult) at System.Net.Browser.BrowserHttpWebRequest.<>c_DisplayClass5.b_4(Object sendState) at System.Net.Browser.AsyncHelper.<>c_DisplayClass4.b_1(Object sendState) --- End of inner exception stack trace --- at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state) at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult) at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result) --- End of inner exception stack trace --- at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result) at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result) at Syst开发者_开发百科em.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result) at System.ServiceModel.ClientBase1.ChannelBase1.EndInvoke(String methodName, Object[] args, IAsyncResult result) at EvaluaionAncillaryControl.EvalDrawingService.DrawingServiceClient.DrawingServiceClientChannel.EndGetEvalAreaDrawing(IAsyncResult result) at EvaluaionAncillaryControl.EvalDrawingService.DrawingServiceClient.EvaluaionAncillaryControl.EvalDrawingService.IDrawingService.EndGetEvalAreaDrawing(IAsyncResult result) at EvaluaionAncillaryControl.EvalDrawingService.DrawingServiceClient.OnEndGetEvalAreaDrawing(IAsyncResult result) at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)}


(RESOLUTION) I was able to find the answer by observing what was being done in the first link in the answer from @rboarman. The link is to a blog writtent by Omar Al Zabir. http://omaralzabir.com/dynamically-set-wcf-endpoint-in-silverlight/

I used the below method:

public class DynamicEndpointHelper
{
// Put the development server site URL including the trailing slash
// This should be same as what's set in the Dropthings web project's 
// properties as the URL of the site in development server
private const string BaseUrl = "http://localhost:8000/Dropthings/";

public static string ResolveEndpointUrl(string endpointUrl, string xapPath)
{
    string baseUrl = xapPath.Substring(0, xapPath.IndexOf("ClientBin"));
    string relativeEndpointUrl = endpointUrl.Substring(BaseUrl.Length);
    string dynamicEndpointUrl = baseUrl + relativeEndpointUrl;
    return dynamicEndpointUrl;
}
}

and called it in this manner:

DynamicEndpointHelper.ResolveEndpointUrl(service.Endpoint.Address.Uri.ToString(), 
    App.Current.Host.Source.ToString()));

This allowed me to see that the proper way would have been to call use an address like:

http://MyServer/Services/MyService.svc/Services //This is what I specified it in the web.config

instead of just

http://MyServer/Services/MyService.svc/

I thought that the address "Services" in the service config was a relative address to my .svc file, but obviously I was wrong.


I found these which looks promising:

http://omaralzabir.com/dynamically-set-wcf-endpoint-in-silverlight/

http://blogs.artinsoft.net/mrojas/archive/2011/03/23/dynamically-change-wcf-endpoint.aspx

Also, here's some code from my server project where I can change the end point on the fly using channels. I haven't tried it from Silverlight. it does work from the server side.

    /// <summary>
    /// This class contains utility methods related to invoking WCF services.
    /// http://msdn.microsoft.com/en-us/library/ms734681.aspx
    /// </summary>
    public static class ServiceInvoker
    {
        /// <summary>
        /// Alternative to the using statement to handle exceptions thrown by the Close method
        /// by calling the Abort method to ensure the transition to the Closed state.
        /// </summary>
        /// <param name="action">
        /// The action.
        /// </param>
        /// <typeparam name="TService">
        /// The service type.
        /// </typeparam>
        public static void UsingProxy<TService>(Action<TService> action)
            where TService : class, ICommunicationObject, IDisposable, new()
        {
            // create an instance of TService and invoke the action
            TService service = new TService();
            service.InvokeAction(action);
        }
        /// <summary>
        /// Alternative to the using statement to handle exceptions thrown by the Close method
        /// by calling the Abort method to ensure the transition to the Closed state.
        /// </summary>
        /// <param name="action">
        /// The action.
        /// </param>
        /// <typeparam name="TService">
        /// The service type.
        /// </typeparam>
        public static void UsingChannel<TService>(ChannelFactory<TService> channelFactory, Action<TService> action)
            where TService : class
        {
            // create an instance of TService and invoke the action
            TService service = channelFactory.CreateChannel();
            service.InvokeAction(action);
        }
        /// <summary>
        /// Alternative to the using statement to handle exceptions thrown by the Close method
        /// by calling the Abort method to ensure the transition to the Closed state.
        /// </summary>
        /// <param name="action">
        /// The action.
        /// </param>
        /// <typeparam name="TService">
        /// The service type.
        /// </typeparam>
        public static void UsingFactory<TService>(Action<TService> action)
            where TService : class
        {
            // TODO: cache the channel factory of TService
            ChannelFactory<TService> factory = new ChannelFactory<TService>("*");
            // create an instance of TService and invoke the action
            TService service = factory.CreateChannel();
            service.InvokeAction(action);
        }
        /// <summary>
        /// Invokes an action on a service then disposes the service channel.
        /// </summary>
        /// <typeparam name="TService">
        /// The service type.
        /// </typeparam>
        /// <param name="service">
        /// The service.
        /// </param>
        /// <param name="action">
        /// The action.
        /// </param>
        private static void InvokeAction<TService>(this TService service, Action<TService> action)
            where TService : class
        {
            try
            {
                // invoke action with service as its parameter
                action(service);
            }
            catch (Exception)
            {
                // todo: add logging here
                throw;
            }
            finally
            {
                // always close or abort the service channel
                ((ICommunicationObject)service).CloseOrAbort();
            }
        }
    }

Here's how I use it:

ServiceInvoker.UsingChannel<IMyProxy>(new ChannelFactory<IMyProxy>(new NetTcpBinding(), myServer.EndPointReference.Address), server =>
            {
                result = server.CallAMethod(passSomeData);
            });
0

精彩评论

暂无评论...
验证码 换一张
取 消