簡體   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