📜 ⬆️ ⬇️

asp.net: useful things, part three

I have already given an example of using attributes in C # and specifically in asp.net in a previous article. There the simplest attribute was declared and some logic to check it was executed. This time I would like to show another useful attribute that is a bit more complicated than the previous one, but much more useful.

In asp.net, you almost always have to deal with query string parameters. Access to them, as is known, is done through Request, for example, Request.QueryString [“id”] will return the value of the id or null parameter if the parameter in the string is not defined. This is quite convenient until you get tired of checking for null each time before assigning a variable. For example, if we want to initialize int id with the value of the id parameter of the query string, we need to write something like the following code:
 int id = Request.QueryString [“id”] == null?  0: Convert.ToInt32 (Request.QueryString [“id”]);


A bit tiring, aren't you? In addition, if the task is to pre-check the initialization of the required parameter of the query string, then the work increases. In one place we check, in another we assign. I propose to combine all the work on getting, checking and initializing the parameters of the query string in one place. And here attributes will help again. Declare the following attribute:
     [AttributeUsage (AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
     sealed public class QueryStringBindingAttribute: Attribute
     {
         public string QueryStringItem
         {
             get;
             private set;
         }
         public bool ThrowOnNull
         {
             get;
             private set;
         }
         public object DefaultValue
         {
             get;
             private set;
         }

         public QueryStringBindingAttribute (string p_queryStringItem)
         {
             SetQueryStringBindingAttribute (p_queryStringItem, false, null);
         }

         public QueryStringBindingAttribute (string p_queryStringItem, bool p_throwOnNull)
         {
             SetQueryStringBindingAttribute (p_queryStringItem, p_throwOnNull, null);
         }

         public QueryStringBindingAttribute (string p_queryStringItem, bool p_throwOnNull, object p_defaultValue)
         {
             SetQueryStringBindingAttribute (p_queryStringItem, p_throwOnNull, p_defaultValue);
         }

         void SetQueryStringBindingAttribute (string p_queryStringItem, bool p_throwOnNull, object p_defaultValue)
         {
             if (String.IsNullOrEmpty (p_queryStringItem))
                 throw new Exception (Properties.Settings.Default.InvalidParamsError);

             this.QueryStringItem = p_queryStringItem;
             this.ThrowOnNull = p_throwOnNull;
             this.DefaultValue = p_defaultValue;
         }
     }


It says that the attribute will be applicable to the fields and properties of the class, will not be inherited, and will be applicable only once. The attribute declares the following properties: the actual name of the parameter of the query string, the painful value “whether an exception should be raised” and the default value The last property is another useful thing. It is often necessary to set a default value when there is no parameter value and build a page based on it. The DefaultValue property is precisely for this purpose defined. The attribute defines three constructors for different situations; in the simplest case, the attribute is specified to select a specific parameter from the query string, an exception is not generated and there is no default value.

Logic is required to process such an attribute. I quote it below:
     public class QueryStringBinding
     {
         Page page;

         public QueryStringBinding (Page p_page)
         {
             if (p_page == null)
                 throw new Exception ("Invalid parameter");

             this.page = p_page;
         }

         private void SetMemberValue (MemberInfo p_member, object value)
         {
             if (p_member == null)
                 throw new Exception ("Invalid parameter");

             Type _memberType = p_member.GetMemberType ();

             if (_memberType == typeof (string))
             {
                 p_member.SetValue (page, value.ToString ());
             }
             else if (_memberType == typeof (bool))
             {
                 p_member.SetValue (page, Convert.ToBoolean (value));
             }
             else if (_memberType == typeof (int))
             {
                 p_member.SetValue (page, Convert.ToInt32 (value));
             }
             else if (_memberType == typeof (int?))
             {
                 p_member.SetValue (page, Convert.ToInt32 (value));
             }
             else if (_memberType == typeof (bool?))
             {
                 p_member.SetValue (page, Convert.ToBoolean (value));
             }
             else
                 throw new Exception (Properties.Settings.Default.UsupportedTypeError);
         }

         public void InitQueryStringProperties ()
         {
             Type _type = page.GetType (). Namespace == null?  page.GetType (): page.GetType (). BaseType;

             MemberInfo [] _members = _type.FindMembers (MemberTypes.Field | MemberTypes.Property,
                 BindingFlags.DeclaredOnly |  BindingFlags.Static |  BindingFlags.Instance |  BindingFlags.NonPublic |  BindingFlags.Public,
                 null, null);

             foreach (MemberInfo member in _members)
             {
                 bool _isDef = Attribute.IsDefined (member, typeof (QueryStringBindingAttribute));
                 if (_isDef)
                 {
                     Attribute _attr = Attribute.GetCustomAttribute (member, typeof (QueryStringBindingAttribute));
                     string _requestItem = page.Request.QueryString [(_ attr as QueryStringBindingAttribute) .QueryStringItem];

                     if (! String.IsNullOrEmpty (_requestItem))
                     {
                         SetMemberValue (member, _requestItem);
                     }
                     else
                     {
                         object _defaultValue = (_attr as QueryStringBindingAttribute) .DefaultValue;
                         if (_defaultValue! = null)
                         {
                             SetMemberValue (member, _defaultValue);
                         }
                         else
                         {
                             if ((_attr as QueryStringBindingAttribute) .ThrowOnNull)
                                 throw new Exception (String.Format ("Parameter {0} was not specified in the query string",
                                     (_attr as QueryStringBindingAttribute) .QueryStringItem));
                         }
                     }
                 }
             }
         }
     }


The methods described in the first article are widely used here. As can be seen from the implementation, only the types string, int, bool, int are supported? and bool? .. For me this is enough, but I am sure that the list can and should be expanded. I don’t know how interesting the implementation details are, if it’s incomprehensible to someone, I’m sure to sign for it, but for now, without setting what’s what, I’ll immediately give an example of usage:
     [QueryStringBinding ("bankid")]
     public int?  BankId {get;  set;  }

     [QueryStringBinding ("cityid", true)]
     public int CityId {get;  set;  }

     [QueryStringBinding ("branchId", false, 0)]
     public int BranchId {get;  set;  }

     protected override void OnInit (EventArgs e)
     {
         QueryStringBinding qsbObject = new QueryStringBinding (this);
         qsbObject.InitQueryStringProperties ();            
         base.OnInit (e);
     }


In this example, when the page is initialized, the class properties are assigned the values ​​of the query string parameters. If the cityid in the query string there is no exception. If branchId is not present, then the property is assigned a default value = 0;
Comment: once again I write that this implementation does not claim to be perfect code. With your help, I would like to make it even better.
Comment2: The construction “Type _type = page.GetType (). Namespace == null? page.GetType (): page.GetType (). BaseType; ”introduced to solve the problem described in my second article. If anyone knows how to solve it more elegantly, please comment.

')

Source: https://habr.com/ru/post/24930/


All Articles