zoukankan      html  css  js  c++  java
  • Asp.net2.0中的提供程序dashcommerce中的税率计算提供程序

      commerce starter kit (commerce Starter kit 随书 asp.net2.0典型项目开发 ---应用篇光盘中的一套程序,他改自dashcommerce) 中,有很多自定义提供程序的应用,比方在线支付模块,税率计算模块等,

     在网站App_Code/Services/TaxProvider/下面是相关的代码实现

     首先是配置节的代码,来自文件:TaxServiceSection.cs

    namespace Commerce.Providers
    {

     

        public class TaxServiceSection : ConfigurationSection
        {
            [ConfigurationProperty("providers")]
            public ProviderSettingsCollection Providers
            {
                get { return (ProviderSettingsCollection)base["providers"]; }
            }

            [StringValidator(MinLength = 1)]
            [ConfigurationProperty("defaultProvider",
                DefaultValue = "SqlTaxProvider")]
            public string DefaultProvider
            {
                get { return (string)base["defaultProvider"]; }
                set { base["defaultProvider"] = value; }
            }


     
     
        }
    }

    这里声明了TaxServiceSection类,这个类有一个DefaultProvider属性,以及一个Providers集合属性,集合属性使用的.net框架提供的ProviderSettingsCollection类,对于这个类大家应该不陌生,像MemberShip,RoleManager 配置节里的Providers就是对应这个类的,ProviderSettingsCollection 是ProviderSettings的集合类,ProviderSettings 继承于ConfigurationElement, ProviderSetttings 里面定义了一个name ,跟type属性,而Parameters 属性是一个NameValueCollection 类型的,应此如Membership 配置提供程序中(<providers><add name="" type="" .... /></providers>的其他属性如connectionStringName,enablePasswordRetrieval等多是保存在Parameters中的,参考下面的membership节

      <membership defaultProvider="AspNetSqlMembershipProvider" userIsOnlineTimeWindow="15" hashAlgorithmType="">
       <providers>
        <clear/>
        <add connectionStringName="LocalSqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="CSK" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" passwordStrengthRegularExpression="" minRequiredPasswordLength="4" minRequiredNonalphanumericCharacters="0" name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
       </providers>
      </membership>

     TaxServiceSection 在配置文件中对应的声明如下

     <section name="TaxService" type="Commerce.Providers.TaxServiceSection" allowDefinition="MachineToApplication" restartOnExternalChanges="true" requirePermission="false"/>

     具体的配置如下

     <TaxService defaultProvider="StrikeIronTaxProvider">
      <providers>
       <clear />
       <add serviceKey=""   name="StrikeIronTaxProvider" type="Commerce.Providers.StrikeIronTaxProvider" />
      </providers>
     </TaxService>

     以上是TaxServiceSection的介绍,TaxServiceSection的作用就是从web.config中读取配置数据,

     下面我们来看TaxProvider类,由于各地计算税率的方法不同因此这里把TaxProvider类声明为一个抽象类

      public abstract class TaxProvider : ProviderBase ,这个类继承自ProviderBase,ProviderBase是所有使用提供程序模型类的基类.在TaxProvider类中定义了一些属性如ServiceLogin,ServiceKey等,另外重要的是定义的三个抽象方法如下

            public abstract decimal GetTaxRate(string zip);
            public abstract decimal GetTaxRate(Commerce.Common.USState state);
            public abstract DataSet GetTaxTable(Commerce.Common.USState state);

     这三个抽象方法在具体的TaxProvider类中被实现,Commerce starter kit 给出了三个TaxProvider类的具体实现,他们是 StrikeIronTaxProvider.cs,FlatRateTaxProvider.cs以及ZeroTaxRateProvider.cs.

    以StrikeIronTaxProvider为例, 里面首先是实现了 public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) 方法,这个方法是必需实现的,因为Provider被实例化后,需要设置一些属性,而这些属性就是保存在web.config相应配置节中<providers>元素中的<add .../>元素中的属性,

    下面这段代码摘自StrikeIronTaxprovider.cs中的Initialize方法

            public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
            {
                base.Initialize(name, config);
                try
                {
                    this.ServiceKey = config["serviceKey"].ToString();
                    //this.ServicePassword = config["servicePassword"].ToString();
                    //this.ServiceLogin = config["serviceLogin"].ToString();
                }
                catch
                {
                    throw new Exception("The Service Key must be set for the StrikeIronTaxProvider to work");
                }

            }

     提供程序模型提供了通过配置来替换具体实现类的编程模型,应此提供程序会通过反射机制来架载,具体实例化的时间是,对于应类被第一次调用时实例化,一般情况下只实例化一次. TaxService.cs文件中定义的TaxService类,封装了TaxProvider类的使用,他对外提供一组静态方法,将具体的TaxProvider类实例保存在静态字段中

     private static TaxProvider _provider = null,静太字段对应类的生命周期等同于应用程序的周期(Asp.net 的 Application  )

    下面是这个类的代码:

     public class TaxService
        {
            #region Provider-specific bits
            private static TaxProvider _provider = null;
            private static object _lock = new object();

            public TaxProvider Provider
            {
                get { return _provider; }
            }

            public static TaxProvider Instance
            {
                get
                {
                    LoadProviders();
                    return _provider;
                }
            }
            private static void LoadProviders()
            {
                // Avoid claiming lock if providers are already loaded
                if (_provider == null)
                {
                    lock (_lock)
                    {
                        // Do this again to make sure _provider is still null
                        if (_provider == null)
                        {
                            // Get a reference to the <TaxServiceSection> section
                            TaxServiceSection section = (TaxServiceSection)
                                WebConfigurationManager.GetSection
                                ("TaxService");

                            // Only want one provider here
                             _provider = (TaxProvider)ProvidersHelper.InstantiateProvider
                                (section.Providers[0], typeof(TaxProvider));

                           
                            if (_provider == null)
                                throw new ProviderException
                                    ("Unable to load default TaxProvider");
                        }
                    }
                }
            }
            #endregion


            public static decimal CalculateAmountByZIP(string zipCode, decimal subTotal) {
                decimal dOut = 0;
       try {
        decimal dRate = Instance.GetTaxRate(zipCode);
        dOut = subTotal * dRate;
       } catch(Exception x) {
        throw new ApplicationException("Tax calculation failed: " + x.Message, x);
       }
                return dOut;
            }
            public static decimal GetUSTaxRate(string zipCode)
            {
                return Instance.GetTaxRate(zipCode);

            }
            public static decimal GetUSTaxRate(Commerce.Common.USState state)
            {
                return Instance.GetTaxRate(state);
            }
        }

    我们注意到LoadProviders()方法中使用双lock语句来保证只实例化一个TaxProvider 的具体类(具体看配置文件),LoadProviders()中首先获取TaxServieceSection 节中的配置数据

             // Get a reference to the <TaxServiceSection> section
      TaxServiceSection section = (TaxServiceSection)WebConfigurationManager.GetSection("TaxService");

     接着是实例化

                            // Only want one provider here
                             _provider = (TaxProvider)ProvidersHelper.InstantiateProvider
                                (section.Providers[0], typeof(TaxProvider));

    这里使用ProvidersHelper.InstantiateProvider() 方法

     下面是通过Reflector 找到的实现代码

    public static class ProvidersHelper
    {
        // Methods
        [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Low)]
        public static ProviderBase InstantiateProvider(ProviderSettings providerSettings, Type providerType)
        {
            ProviderBase base2 = null;
            try
            {
                string str = (providerSettings.Type == null) ? null : providerSettings.Type.Trim();
                if (string.IsNullOrEmpty(str))
                {
                    throw new ArgumentException(SR.GetString("Provider_no_type_name"));
                }
                Type c = ConfigUtil.GetType(str, "type", providerSettings, true, true);
                if (!providerType.IsAssignableFrom(c))
                {
                    throw new ArgumentException(SR.GetString("Provider_must_implement_type", new object[] { providerType.ToString() }));
                }
                base2 = (ProviderBase) HttpRuntime.CreatePublicInstance(c);
                NameValueCollection parameters = providerSettings.Parameters;
                NameValueCollection config = new NameValueCollection(parameters.Count, StringComparer.Ordinal);
                foreach (string str2 in parameters)
                {
                    config[str2] = parameters[str2];
                }
                base2.Initialize(providerSettings.Name, config);
            }
            catch (Exception exception)
            {
                if (exception is ConfigurationException)
                {
                    throw;
                }
                throw new ConfigurationErrorsException(exception.Message, providerSettings.ElementInformation.Properties["type"].Source, providerSettings.ElementInformation.Properties["type"].LineNumber);
            }
            return base2;
        }

        [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Low)]
        public static void InstantiateProviders(ProviderSettingsCollection configProviders, ProviderCollection providers, Type providerType)
        {
            foreach (ProviderSettings settings in configProviders)
            {
                providers.Add(InstantiateProvider(settings, providerType));
            }
        }
    }

     

     注意红色的代码,这几行代码的功能是通过反射实例化类,并且将ProviderSettings中的Parameters属性复制到config中,

    完成后调用ProviderBase的initialize方法, base2.Initialize(providerSettings.Name, config);

     //===================

    internal static object CreateNonPublicInstance(Type type, object[] args)
    {
        return Activator.CreateInstance(type, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, args, null);
    }

    最终调用的是 Activator.CreateInstance方法

  • 相关阅读:
    HDU 1863 畅通工程(Kruskal)
    HDU 1879 继续畅通工程(Kruskra)
    HDU 1102 Constructing Roads(Kruskal)
    POJ 3150 Cellular Automaton(矩阵快速幂)
    POJ 3070 Fibonacci(矩阵快速幂)
    ZOJ 1648 Circuit Board(计算几何)
    ZOJ 3498 Javabeans
    ZOJ 3490 String Successor(模拟)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
  • 原文地址:https://www.cnblogs.com/wdfrog/p/1266923.html
Copyright © 2011-2022 走看看