繁体   English   中英

使用WCF“远程处理”.NET类库的最佳实践

[英]Best practices on “remoting” a .NET class library with WCF

我有一个包含60多个类和许多公共方法的大型.NET 4.5类库。 这可以作为我的应用程序的编程接口。 现在我想使用WCF通过网络调用此库。 这样做的最佳做法是什么?

一种天真的方法是使用WCF服务库来包装我的类库,该服务库复制原始类库的类和方法结构,其中每个方法都有一个方法。 然而,这似乎是过度的,并且违背了制造粗糙而不是繁琐的网络接口的原则。 那我该如何构建WCF服务库呢? 它应该有什么结构? 有没有公​​认的最佳实践指导? 谢谢。

不知道这是否是“最佳”练习,但我已经看到了这样做:

使数据契约成为一个单独的方法,该方法将操作和参数数组作为参数。 然后,在服务器上,通过反射获取实现方法,并简单地传递参数数组。 这是我放在一起的快速样本(经过测试,可行)。

合同:

namespace GenericWcfService
{
    [ServiceKnownType(typeof(Pair))] //there's another way to add more, look it up
    [ServiceContract]
    public interface ICalculatorService
    {
        [OperationContract]
        OperationResult GetResult(Operation op, object[] parameteres);
    }

    public enum Operation
    {
        Add,
        Substract,
        Multiply,
        Divide,
        Print,
        AddPair
    }

    [DataContract]
    public class OperationResult
    {
        [DataMember]
        public object Result { get; set; }

        [DataMember]
        public string Error { get; set; }
    }

    [DataContract]
    public class Pair
    {
        [DataMember]
        public int V1;
        [DataMember]
        public int V2;
    }
}

服务器:

namespace GenericWcfService
{
    public class CalculatorService : ICalculatorService
    {
        public OperationResult GetResult(Operation op, object[] parameteres)
        {
            var calc = new CalculatorImpl();
            var method = typeof(CalculatorImpl).GetMethod(op.ToString());

            var result = new OperationResult();
            if (method == null) { result.Error = "Incompatible"; return result; }
            var mParameters = method.GetParameters();
            if (mParameters.Length != parameteres.Length) { result.Error = "Incompatible"; return result; }
            for (int i = 0; i < parameteres.Length; i++)
            {
                try
                {
                    var paramVal = Convert.ChangeType(parameteres[i], mParameters[i].ParameterType);
                }
                catch (Exception)
                {
                    { result.Error = $"Parameter [{i}]({mParameters[i]})={parameteres[i]} is incompatible"; return result; }
                }
            }


            try
            {
                result.Result = method?.Invoke(calc, parameteres);
            }
            catch (Exception e)
            {
                result.Error = e.Message;
            }
            return result;
        }
    }

    public class CalculatorImpl
    {
        public int Add(int p1, int p2)
        {
            return p1 + p2;
        }

        public string Print(string text, int n1)
        {
            return $"{text}: {n1}";
        }

        public int AddPair(Pair p)
        {
            return p.V1 + p.V2;
        }
    }
}

客户:

class Program
{
    static void Main(string[] args)
    {
        var calc = new CalculatorServiceClient();
        var result = calc.GetResult(Operation.Add, new object[] { 2, 3 });
        if (string.IsNullOrEmpty(result.Error))
            Console.WriteLine(result.Result);
        else
            Console.WriteLine(result.Error);

        result = calc.GetResult(Operation.Print, new object[] { "result", result.Result });
        if (string.IsNullOrEmpty(result.Error))
            Console.WriteLine(result.Result);
        else
            Console.WriteLine(result.Error);

        result = calc.GetResult(Operation.Add, new object[] { 2, "c3" });
        if (string.IsNullOrEmpty(result.Error))
            Console.WriteLine(result.Result);
        else
            Console.WriteLine(result.Error);

        result = calc.GetResult(Operation.AddPair, new object[] { new Pair { V1 = 3, V2 = 4 } });
        if (string.IsNullOrEmpty(result.Error))
            Console.WriteLine(result.Result);
        else
            Console.WriteLine(result.Error);

        Console.ReadKey();
    }
}

输出:

5
result: 5
Parameter [1](Int32 p2)=c3 is incompatible
7
  1. 我会提到参数验证,但后来我继续完成它,使用反射来验证计数和object参数可以转换。
  2. 然后我想到了复杂的对象......是的,它们可以作为object发送到参数数组中(并且它们通过上面的方式得到了正确的验证),但它们需要由服务公开。 要在服务定义中包含未使用的类,请使用ServiceKnownType属性。
  3. 拥有这种服务定义会打开一个全新的机会(对于混乱!:))您可以在服务器上的Operation枚举末尾添加值,而不是破坏客户端。 或者使用string作为操作代码(而不是使用复杂类型作为参数,参见2.)并且疯狂! 多个版本的服务器与多个版本的客户端协商,部分服务器实现......变得可能,显然需要一些版本控制和发现逻辑(在中央服务上?)

总结:我在上面有一点被带走了,我在那里描述的必须与WCF服务的最佳实践完全相反。 如果我没有弄错,更改服务器打破客户端的事实被认为是WCF的优势之一。 但我仍然认为上述解决方案对某些情况有效

  • 快速地在服务中包装一个不会改变的大型库或者客户不介意不总是得到响应

  • 当客户众多且无法快速更新时允许一定程度的灵活性,因此不同版本需要并行工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM