开发者

WCF CommunicationException on returning Data

开发者 https://www.devze.com 2023-02-16 10:50 出处:网络
Here at work we have developed a SOAP WCF API that can be reached from the outside. Because one of the requirements for the API has changed, I wanted to add a new class to this API to generated the co

Here at work we have developed a SOAP WCF API that can be reached from the outside. Because one of the requirements for the API has changed, I wanted to add a new class to this API to generated the correct paths for certain function calls.

Our API is divided into 3 seperate libraries:

  • One for the objects
  • One for the interfaces
  • One for the implementation.

Clients ofcourse get the first two to work with in scripts, the server has all three.

The class I wish to add to the API looks like this:

namespace TenForce.Execution.API.Objects.Helpers
{
/// <summary>
/// <para>This interface defines the functionality available in the PathHelper for the API.</para>
/// </summary>
public interface IPathHelper
{
    string ApplicationFolder { get; }   // The HomeDataFolder for the application
    string CompanyHomeFolder { get; }   // The HomeDataFolder for the company.
    string CustomFolder { get; }        // The custom folder for professional services.
    string WikiFolder { get; }          // The WIKI folder to store pages.
    string AddinsFolder { get; }        // The AddinFolder to access the addins.
}
}

The actual class implementation looks something like this:

using System.IO;
using System.Runtime.Serialization;
using TenForce.Execution.BUL;
using TenForce.Execution.Framework;

namespace TenForce.Execution.API.Implementation.Helpers
{
/// <summary>
/// <para>This class provides a direct implementation of the IPathHelper for the API implementation
/// and manages all the paths inside the DataHomeFolder structure for the TenForce application.</para>
/// </summary>
[DataContract]
public class PathHelper : Objects.Helpers.IPathHelper
{
    #region Private Fields

    private readonly ParameterBUL _mParameterBul;
    private const Parameter.ParameterId DataHomeFolderId = Parameter.ParameterId.DataHomeFolder;
    private const Parameter.ParameterId CompanyNameId = Parameter.ParameterId.CompanyName;

    #endregion

    #region Constructor

    /// <summary>
    /// <para>Creates a new instance of the PathHelper class</para>
    /// </summary>
    public PathHelper()
    {
        _mParameterBul = new ParameterBUL();
    }

    #endregion

    #region IPathHelper Members

    /// <summary>
    /// <para>Returns the absolute path to the DataHomeFolder of the TenForce Application.</para>
    /// </summary>
    [DataMember]
    public string ApplicationFolder
    {
        get
        {
            return CreatePath(_mParameterBul.GetParameterValue(DataHomeFolderId));
        }
    }

    /// <summary>
    /// <para>Returns the absolute path to the Company DataHomeFolder.</para>
    /// </summary>
    [DataMember]
    public string CompanyHomeFolder
    {
        get
        {
            return CreatePath(Path.Combine(ApplicationFolder, _mParameterBul.GetParameterValue(CompanyNameId)));
        }
    }

    /// <summary>
    /// <para>Returns the absolute path to the Company custom folder.</para>
    /// </summary>
    [DataMember]
    public string CustomFolder
    {
        get
        {
            return CreatePath(Path.Combine(CompanyHomeFolder, @"custom"));
        }
    }

    /// <summary>
    /// <para>Returns the absolute path to the Company wiki folder.</para>
    /// </summary>
    [DataMember]
    public string WikiFolder
    {
        get
        {
            return CreatePath(Path.Combine(CompanyHomeFolder, @"wiki"));
        }
    }

    /// <summary>
    /// <para>Returns the absolute path to the Company addins folder.</para>
    /// </summary>
    [DataMember]
    public string AddinsFolder
    {
        get
        {
            return CreatePath(Path.Combine(CompanyHomeFolder, @"addins"));
        }
    }

    #endregion

    #region Private Members

    /// <summary>
    /// <para>Checks if the specified path exists, and creates the path 
    /// if the system cannot find it.</para>
    /// </summary>
    /// <param name="path">The path to verify.</param>
    private static string CreatePath(string path)
    {
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path);
        return path;
    }

    #endregion
}
}

All by all this is pretty basic stuff. The WCF Service is created dynamicly by us using the Factories and classes available through .NET. The WCF Service is working perfectly for all the code already existing inside the Service.

So I decided to add the following line inside the class that's our Service:

    /// <summary>
    /// <para>Returns the PathHelper to construct the various paths for API Scripts.</para>
    /// </summary>
    /// <returns>An instance of the PathHelper.</returns>
    public Objects.Helpers.IPathHelper GetPathHelper()
    {
        return new Helpers.PathHelper();
    }

    #endregion

When I run the unittests, all tests are working except those that check the functions of the PathHelper, they all end up with the same error message/exception:

Error 1 TestCase 'TenForce.Execution.API.ImplementationTest/HelperTests/CheckApplicationFolderPath' failed: Execute System.ServiceModel.CommunicationException: The remote endpoint no longer recognizes this sequence. This is most likely due to an abort on the remote endpoint. The value of wsrm:Identifier is not a known Sequence identifier. The reliable session was faulted.

Server stack trace: at System.ServiceModel.Channels.ReliableRequestSessionChannel.SyncRequest.WaitForReply(TimeSpan timeout) at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout) at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Ca开发者_JAVA百科ll(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs) 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 TenForce.Execution.API.Contracts.IAPI.GetPathHelper() at TenForce.Execution.API.ServiceClient.ServiceAPI.GetPathHelper() in c:\Users\arne.de.herdt\Documents\Trunk\Robinson\TenForce.Execution.API.ServiceClient\ServiceAPI.cs:line 163 at TenForce.Execution.API.ImplementationTest.HelperTests.CheckApplicationFolderPath() in C:\Users\arne.de.herdt\Documents\Trunk\Robinson\TenForce.Execution.API.ImplementationTest\HelperTests.cs:line 56 c:\Users\arne.de.herdt\Documents\Trunk\Robinson\TenForce.Execution.API.ServiceClient\ServiceAPI.cs 163

I'm clueless what's going wrong, or what I'm missing. The code is working for what's already there, but when I added my piece, it goes haywire, yet the existing functions keep working. it's mine that cause a problem.


The error seems strange to me, maybe it is related to the way you are dynamically generating the services.

However, that class is not serializable, the properties on that class are read only (do not have a set accessor). For marking a property as DataMember the properties need to have a set accesor, even if it is marked as private. From MSDN:

Note Properties to which the DataMemberAttribute attribute has been applied must have both get and set fields; they cannot be get-only or set-only.

DataMember Documentation

The only thing you may want to serialize in that class is the m_ParameterBul variable, so marking that as DataMember and removing all the other DataMember attributes from the readonly properties will do it.

You should note that if m_ParameterBul is not server dependant there is not need to create this class on the server side, because everything is client related. In that case you should create it directly on the clients.

Hope it helps!

/// <summary>
/// <para>This class provides a direct implementation of the IPathHelper for the API implementation
/// and manages all the paths inside the DataHomeFolder structure for the TenForce application.</para>
/// </summary>
[DataContract]
public class PathHelper : Objects.Helpers.IPathHelper
{
    #region Private Fields
    [DataMember]
    private readonly ParameterBUL _mParameterBul;
    private const Parameter.ParameterId DataHomeFolderId = Parameter.ParameterId.DataHomeFolder;
    private const Parameter.ParameterId CompanyNameId = Parameter.ParameterId.CompanyName;

    #endregion

    #region Constructor

    /// <summary>
    /// <para>Creates a new instance of the PathHelper class</para>
    /// </summary>
    public PathHelper()
    {
        _mParameterBul = new ParameterBUL();
    }

    #endregion

    #region IPathHelper Members

    /// <summary>
    /// <para>Returns the absolute path to the DataHomeFolder of the TenForce Application.</para>
    /// </summary>   
    public string ApplicationFolder
    {
        get
        {
            return CreatePath(_mParameterBul.GetParameterValue(DataHomeFolderId));
        }
    }

    /// <summary>
    /// <para>Returns the absolute path to the Company DataHomeFolder.</para>
    /// </summary>   
    public string CompanyHomeFolder
    {
        get
        {
            return CreatePath(Path.Combine(ApplicationFolder, _mParameterBul.GetParameterValue(CompanyNameId)));
        }
    }

    /// <summary>
    /// <para>Returns the absolute path to the Company custom folder.</para>
    /// </summary>
    public string CustomFolder
    {
        get
        {
            return CreatePath(Path.Combine(CompanyHomeFolder, @"custom"));
        }
    }

    /// <summary>
    /// <para>Returns the absolute path to the Company wiki folder.</para>
    /// </summary>
    public string WikiFolder
    {
        get
        {
            return CreatePath(Path.Combine(CompanyHomeFolder, @"wiki"));
        }
    }

    /// <summary>
    /// <para>Returns the absolute path to the Company addins folder.</para>
    /// </summary>    
    public string AddinsFolder
    {
        get
        {
            return CreatePath(Path.Combine(CompanyHomeFolder, @"addins"));
        }
    }

    #endregion

    #region Private Members

    /// <summary>
    /// <para>Checks if the specified path exists, and creates the path 
    /// if the system cannot find it.</para>
    /// </summary>
    /// <param name="path">The path to verify.</param>
    private static string CreatePath(string path)
    {
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path);
        return path;
    }

    #endregion
}


Thanks to the feedback from the comments and the awnser, the solution is to move the class to the second API implementation, and not make it avaialble through the WCF Service.

The class contains functions and read-only properties, thus the class cannot be serialized by the WCF Service. The final result will be that only scripts can use it, and not the service.

0

精彩评论

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

关注公众号