玩转C科技.NET

从学会做人开始认识这个世界!http://volnet.github.io

导航

[WCF]重载

WCF中的接口不允许有重载:

例如:

namespace WcfServiceLibrary1
{
    // NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in App.config.
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        int Add(int a, int b);

        [OperationContract]
        double Add(double a, double b);

        // TODO: Add your service operations here
    }

}

namespace WcfServiceLibrary1
{
    // NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in App.config.
    public class Service1 : IService1
    {
        public int Add(int a, int b)
        {
            return a + b;
        }

        public double Add(double a, double b)
        {
            return a + b + 0.0123;  // 0.0123只是为了区别随便写的。
        }

        //More memebers
    }
}

Build这个程序不会报告错误,但是一旦启动则会在WcfSvcHost中显示Error:错误提示如下:

WcfServiceLibrary1.Service1    Error        Cannot have two operations in the same contract with the same name, methods Add and Add in type WcfServiceLibrary1.IService1 violate this rule. You can change the name of one of the operations by changing the method name or by using the Name property of OperationContractAttribute.
[意思是:在一个契约中不能有两个重名操作(方法)……]

解决办法:

1、最简单的做法就是改名,比如一个为AddInt一个为AddDouble让它们的名字大相径庭即可……

2、使用操作契约中的昵称给它加以修改:

namespace WcfServiceLibrary1
{
    // NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in App.config.
    [ServiceContract]
    public interface IService1
    {
        [OperationContract(Name = "AddInt")]
        int Add(int a, int b);

        [OperationContract(Name = "AddDouble")]
        double Add(double a, double b);

        // TODO: Add your service operations here
    }

}

这样在Client端以同样的方式进行处理却会抛出异常

public class CalculatorClient : ClientBase<ConsoleApplicationClient.ServiceReference.IService1>, ConsoleApplicationClient.ServiceReference.IService1
{
    public int Add1(int arg1, int arg2)
    {
        return Channel.Add(arg1, arg2);
    }

    public double Add(double arg1, double arg2)
    {
        return Channel.Add(arg1, arg2);
    }

}

image

分析原因:

旧有代码中我通过修改IService1中的方法名为Add1和Add进行测试,继而Client通过获取可以使用,但是现在我修改WcfServiceLibrary1后,Client并未获取最新的更新,而是直接将旧有Client代码修改为Add和Add,因此依照旧有的Client代码,会抛出以上异常,因此VS中我们需要重新启动我们的WcfSvcHost进程,然后再更新Client的引用。

Update

右键ServiceReference中的具体服务名,“Update Service Reference”后即可。

再次编译后则会有新的提示(未实现接口),将代码修改为:

//public int Add(int arg1, int arg2)
//{
//    return Channel.Add(arg1, arg2);
//}

//public double Add(double arg1, double arg2)
//{
//    return Channel.Add(arg1, arg2);
//}

public int AddInt(int arg1, int arg2)
{
    return Channel.AddInt(arg1, arg2);
}

public double AddDouble(double arg1, double arg2)
{
    return Channel.AddDouble(arg1, arg2);
}

修改后的代码要求按照修改的昵称对现有参数进行命名。

但是assume这是一个已经拥有很大Client logical的程序呢,我们改变interface的结果将导致整个程序无法编译正如:

Console.WriteLine("Int calculate = {0}", calculator.Add1(2, 3));
Console.WriteLine("Double calculate = {0}",calculator.Add(2.0 , 3.1));

则需要进行变换成AddInt和AddDouble才能够重新工作,这样的结果将导致不必要的麻烦(维护成本瞬间提高,整个Client的稳定性无法估计……)

How to do now?

我们最理想的就是改变我们的Proxy,让它有能力实现Overloading,这将涉及到我们的architecture of wcf,在我们Add ServiceReference的同时,我们会生成一个Proxy的类,这个类其实也就是本例中写的CalculatorClient,在你的Client程序目录路径下,你可以找到Reference.cs的文件(<程序文件>\ConsoleApplicationClient\Service References\ServiceReference),或者写一个Class中调用到Channel.×××的时候,右键则可以找到Reference.cs文件,或者将所有隐藏文件打开,在Service References\Reference.svcmap\Reference.cs可以找到……

image

我们可以看到系统为我们自动生成的Proxy类,在这里面我们注意到

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference.IService1")]
public interface IService1 {

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService1/AddInt", ReplyAction="http://tempuri.org/IService1/AddIntResponse")]
int AddInt(int a, int b);

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService1/AddDouble", ReplyAction="http://tempuri.org/IService1/AddDoubleResponse")]
double AddDouble(double a, double b);

//Other Members
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class Service1Client : System.ServiceModel.ClientBase<ConsoleApplicationClient.ServiceReference.IService1>, ConsoleApplicationClient.ServiceReference.IService1 {
//Constructors

public int AddInt(int a, int b) {
    return base.Channel.AddInt(a, b);
}

public double AddDouble(double a, double b) {
    return base.Channel.AddDouble(a, b);
}
//Other Members
}

将这些改成以下样子(对Add×××方法进行重命名,并为OperationContractAttribute添加Name参数的值,使之等于之前的方法名)

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference.IService1")]
public interface IService1 {

    [System.ServiceModel.OperationContractAttribute(Name = "AddInt", Action = "http://tempuri.org/IService1/AddInt", ReplyAction = "http://tempuri.org/IService1/AddIntResponse")]
    int Add(int a, int b);
    [System.ServiceModel.OperationContractAttribute(Name = "AddDouble", Action="http://tempuri.org/IService1/AddDouble", ReplyAction="http://tempuri.org/IService1/AddDoubleResponse")]
    double Add(double a, double b);
//Other Members
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class Service1Client : System.ServiceModel.ClientBase<ConsoleApplicationClient.ServiceReference.IService1>, ConsoleApplicationClient.ServiceReference.IService1 {
//Constructors
    public int Add(int a, int b) {
        return base.Channel.Add(a, b);
    }
    public double Add(double a, double b) {
        return base.Channel.Add(a, b);
    }
//Other Members
}

之后再将所有的调用替换为修改后的重载方法即可完成重载的工作……

class Program
{
    static void Main(string[] args)
    {
        CalculatorClient calculator = new CalculatorClient();
        Console.WriteLine("Int calculate = {0}", calculator.Add(2, 3));
        Console.WriteLine("Double calculate = {0}",calculator.Add(2.0 , 3.1));
        calculator.Close();
    }
}

posted on 2007-11-10 22:59  volnet(可以叫我大V)  阅读(784)  评论(1编辑  收藏  举报

使用Live Messenger联系我
关闭