在C#中使用DS创建“一体化”功能

时间:2008-12-29 09:41:12

标签: c# asp.net design-patterns

在我的网络应用程序中,我使用来自同一个提供程序的几个asmx(Web服务),他们有一个用于此,另一个用于此,但都需要带有身份验证的SOAP标头。

添加身份验证很简单:

public static SoCredentialsHeader AttachCredentialHeader()
{
    SoCredentialsHeader ch = new SoCredentialsHeader();
    ch.AuthenticationType = SoAuthenticationType.CRM5;
    ch.UserId = "myUsername";
    ch.Secret = apUtilities.CalculateCredentialsSecret(
        SoAuthenticationType.CRM5, apUtilities.GetDays(), "myUsername", "myPassword");
    return ch;
}

问题是来自ONE webservice的SoCredentialsHeader来自(派生)我需要向其他人添加相同的代码,例如:

public static wsContact.SoCredentialsHeader AttachContactCredentialHeader()
{
    wsContact.SoCredentialsHeader ch = new wsContact.SoCredentialsHeader();
    ch.AuthenticationType = wsContact.SoAuthenticationType.CRM5;
    ch.UserId = "myUsername";
    ch.Secret = apUtilities.CalculateCredentialsSecret(
        wsContact.SoAuthenticationType.CRM5, apUtilities.GetDays(), "myUsername", "myPassword");
    return ch;
}

public static wsDiary.SoCredentialsHeader AttachDiaryCredentialHeader()
{
    wsDiary.SoCredentialsHeader ch = new wsDiary.SoCredentialsHeader();
    ch.AuthenticationType = wsDiary.SoAuthenticationType.CRM5;
    ch.UserId = "myUsername";
    ch.Secret = apUtilities.CalculateCredentialsSecret(
        wsDiary.SoAuthenticationType.CRM5, apUtilities.GetDays(), "myUsername", "myPassword");
    return ch;
}

有没有办法实现设计模式,只能使用一个适合所有webServices的函数?

有时候我会看到 T 字母,这是一个案例吗?如果是的话,我该如何完成这样的功能?

P.S。我可以传递枚举并使用开关检查枚举名称并应用正确的标题,但每次我需要添加新的WebService时,我需要添加枚举和代码,我正在为此采用先进的技术。

谢谢。

3 个答案:

答案 0 :(得分:3)

在VS解决方案的任何位置创建名为whatever.tt的文件(技巧是.tt扩展名)并粘贴以下代码:

using System;

namespace Whatever
{
    public static class Howdy
    {
<# 
    string[] webServices = new string[] {"wsContact", "wsDiary"};
    foreach (string wsName in webServices)
    {
#>
    public static <#=wsName#>.SoCredentialsHeader AttachContactCredentialHeader()
    {
        <#=wsName#>.SoCredentialsHeader ch = new <#=wsName#>.SoCredentialsHeader();
        ch.AuthenticationType = <#=wsName#>.SoAuthenticationType.CRM5;
        ch.UserId = "myUsername";
        ch.Secret = apUtilities.CalculateCredentialsSecret(<#=wsName#>.SoAuthenticationType.CRM5,
                apUtilities.GetDays(), "myUsername", "myPassword");
        return ch;
    }
    }       
<# } #>
}

然后观看what.cs神奇地出现所需的代码片段。这些被称为T4模板,用于VS中的代码生成。

您需要将这些转换为部分类或扩展方法或其他内容。上面的代码不会“按原样”运行,但你明白了。

答案 1 :(得分:0)

我不知道这是否是你想要考虑的事情,因为它肯定有它的缺点,但是 - 最终这些(varoius SoCredentialsHeader类)都是不同命名空间中相同类定义的所有副本所以一点点的重构你可以简单地拥有一个类和一个方法。

将SoCredentialsHeader类定义复制到您自己的项目中,添加对它的引用并从所有Web服务的代理中删除类定义。 在代理代码文件的顶部添加一个using语句,它不会分辨出来。

基本上你告诉它为所有的Web服务使用相同的类定义(你的)。

显而易见的缺点是,无论何时更新和Web服务引用(并假设所有服务都使用相同的定义),您都必须重复此练习,但我们一直在类似的情况下这样做,并且它工作正常对我们来说非常好。

答案 2 :(得分:0)

我会尝试使用泛型方法,然后使用反射来设置属性:

public static T AttachDiaryCredentialHeader<T>() where T: class
{
    T ch = new T();
    Type objType = ch.GetType();
    PropertyInfo userId = objType.GetProperty("UserId");
    authType.SetValue(ch, "myUsername", null)
    //And so on for the other properties...
    return ch;
}
恕我直言,这有些笨拙,我会将它们分开,除非像上一篇文章中提到的那样,你绝对相信这些服务的定义将保持不变。对其中一个的一个小改动将打破这个。