
asp.net: useful things, part three
I already gave an example of the use of attributes in C # and specifically in asp.net in a previous article. The simplest attribute was declared there and some logic was performed to verify it. This time I would like to show another useful attribute, which is a little more complicated than the previous one, but much more useful.
Asp.net almost always has to deal with query string parameters. Access to them is known to be through Request, for example Request.QueryString [“id”] will return the value of the id parameter or null if the parameter in the string is not defined. This is convenient enough until you get tired of checking for null each time before assigning a variable. For example, if we want to initialize the int id with the value of the id parameter of the query string, we need to write approximately the following code:
A bit tiring, don’t you? In addition, if the task is to pre-verify the initialization of the required parameter of the query string, then the work increases. In one place we check, in another we assign. I suggest combining all the work of getting, checking, and initializing query string parameters in one place. And here again the attributes will help. Declare the following attribute:
It says that the attribute will be applicable to the fields and properties of the class, will not be inherited, and will only be applied once. The following properties are declared in the attribute: the actual name of the query string parameter, the pain value “whether an exception should be raised”, and the default value. The last property is another useful thing. Often, if the parameter value is missing, set some default value and build a page based on it. The DefaultValue property is just for this and is defined. Three constructors are defined in the attribute 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 bring it below:
The methods described in the first article are widely used here. As you can see from the implementation, only the types string, int, bool, int are supported? and bool? .. For me this is enough, but I'm sure that it is possible and necessary to expand the list. I don’t know how interesting the implementation details are, if someone doesn’t understand it, I’ll definitely sign it, but for now, without scheduling, I’ll give an example of use:
In this example, when the page is initialized, the class properties are assigned the values of the query string parameters. If cityid is not in the query string, an exception will be thrown. If branchId is not present, then the property will be assigned the 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 of “Type _type = page.GetType (). Namespace == null? page.GetType (): page.GetType (). BaseType; ”was introduced to solve the problem described in my second article. If anyone knows how to solve it more elegantly, please comment.
Asp.net almost always has to deal with query string parameters. Access to them is known to be through Request, for example Request.QueryString [“id”] will return the value of the id parameter or null if the parameter in the string is not defined. This is convenient enough until you get tired of checking for null each time before assigning a variable. For example, if we want to initialize the int id with the value of the id parameter of the query string, we need to write approximately the following code:
int id = Request.QueryString [“id”] == null? 0: Convert.ToInt32 (Request.QueryString [“id”]);
A bit tiring, don’t you? In addition, if the task is to pre-verify the initialization of the required parameter of the query string, then the work increases. In one place we check, in another we assign. I suggest combining all the work of getting, checking, and initializing query string parameters in one place. And here again the attributes will help. 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 only be applied once. The following properties are declared in the attribute: the actual name of the query string parameter, the pain value “whether an exception should be raised”, and the default value. The last property is another useful thing. Often, if the parameter value is missing, set some default value and build a page based on it. The DefaultValue property is just for this and is defined. Three constructors are defined in the attribute 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 bring 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 ("The parameter {0} is not specified in the query string", (_attr as QueryStringBindingAttribute) .QueryStringItem)); } } } } } }
The methods described in the first article are widely used here. As you can see from the implementation, only the types string, int, bool, int are supported? and bool? .. For me this is enough, but I'm sure that it is possible and necessary to expand the list. I don’t know how interesting the implementation details are, if someone doesn’t understand it, I’ll definitely sign it, but for now, without scheduling, I’ll give an example of use:
[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 cityid is not in the query string, an exception will be thrown. If branchId is not present, then the property will be assigned the 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 of “Type _type = page.GetType (). Namespace == null? page.GetType (): page.GetType (). BaseType; ”was introduced to solve the problem described in my second article. If anyone knows how to solve it more elegantly, please comment.