ASP.Net 4 Web.Config Changes

by Heathesh 5. May 2010 06:23

UPDATE: Before using web.config transforms as indicated in point 2 below, please view this known issue: Web.config transform writes extra line break/spaces to values elements under applicationSettings section

With the release of .Net 4 and ASP.Net 4.0 there have been two major changes to the web.config that I really like. I personally think these changes address two very useful features that all developers should know about:

1. The file has been refactored

The web.config has now been refactored, and with ASP.Net 4 a lot of the settings that were previously found in the web.config file have now been moved to the machine.config file. This significantly reduces the size of the file, which I think is a great bonus.

With this change, your web.config file can be EMPTY or alternatively simply contain just the following section:

    <?xml version="1.0"?>
        <configuration>
            <system.web>
                <compilation targetFramework="4.0" />
            </system.web>
        </configuration>


2. Web.config transformations

Web.config transformations cater for moving your application between your relevant environments (e.g. Development, QA, Production). The transformations work on the relevant configurations you setup.

To create your own Configuration build with configuration transformations, create a new ASP.Net Web Application in Visual Studio 2010. Next, in the menu select "Build" and then "Configuration Manager". In the "Active Solution Configuration" drop down, select "New". Name the relevant configuration, for example I'm calling mine "Development" and copying the settings from the "Debug" configuration.

Make sure "Create new project configurations" is selected. Once you click okay, you will see your Web.config file now has a "+" next to it in your solution explorer.

If you don't see the "+", build you solution, right click the web.config file and select "Add Config Transformations".

You will see for each of your build configurations there will be a "Web.[Build Configuration Name].config" file. If you open any of these files, you will see place holders for different sections of your original web.config file.

To change settings per your relevant build configuration, check out the following MSDN Article: Web.config Transformation Syntax for Web Application Project Deployment

Happy deploying!

Tags: , , , , ,

Development | .Net | Visual Studio 2010 | VS2010

Dynamic Data: Prevent inserting and deleting for a specific table

by Heathesh 7. February 2010 04:04

I was using a Dynamic Data Entities Web Application, and my requirement was to have a specific setup table that would only ever have one prepopulated row. This meant that the user should never be allowed to insert a new record, or delete the current record from the table. They should only ever be allowed to edit the record.

To accomplish this, I started off creating a custom attribute that I was going to apply to the specific table's scaffolding. The primary use of scaffolding in Dynamic Data is to hide and display specific fields and tables as required. So to begin with, I personally always create a class to be used for scaffolding for every table within my Dynamic Data site. For example, the table I was currently working with is called SiteSetup, and the scaffolding class I created looked like so:

    using System.ComponentModel.DataAnnotations; //add this using for the MetadataType attribute

    //The namespace used here must be the same as your Entity Model namespace. The best way (if you
    //don't already know the namespace) to find out the correct namespace is to expand your .edmx file
    //and then open the Designer.cs file and you will see the namespace there
    namespace Heathesh.Com.Entity
    {
        /// <summary>
        /// Partial class of my MetaTable, using the MetadataType attribute to indicate the
        /// class I'm using to save my scaffolding info
        /// </summary>
        [MetadataType(typeof(SiteSetupMetaData))]
        public partial class SiteSetup
        {

        }

        public class SiteSetupMetaData
        {
            /// <summary>
            /// I don't want the user to see the Id field, because in this case
            /// the Id field is an int with an Indentity, so the user will never
            /// need to insert or change this
            /// </summary>
            [ScaffoldColumn(false)]
            public object Id { get; set; }
        }
    }


Pay attention to the comments above, especially regarding the namespace. Now I had to create an attribute to indicate that I specifically didn't want to allow insert or delete for this table, so I created my attribute like so:

    using System;

    namespace Heathesh.Com.Entity.Attributes
    {
        /// <summary>
        /// Custom behaviour attribute to be used on MetaTables to prevent inserts and deletes where
        /// required
        /// </summary>
        [AttributeUsage(AttributeTargets.Class)]
        public class CustomBehaviour : System.Attribute
        {
            #region Public Properties
            /// <summary>
            /// Gets or sets a bool indicating whether or not to allow inserts
            /// </summary>
            public bool AllowInsert
            {
                get;
                set;
            }

            /// <summary>
            /// Gets or sets a bool indicating whether or not to allow deletes
            /// </summary>
            public bool AllowDelete
            {
                get;
                set;
            }
            #endregion

            #region Constructor
            /// <summary>
            /// Default constructor forcing the user to indicate whether to allow inserts and deletes
            /// </summary>
            /// <param name="allowInsert"></param>
            public CustomBehaviour(bool allowInsert, bool allowDelete)
            {
                AllowInsert = allowInsert;
                AllowDelete = allowDelete;
            }
            #endregion
        }
    }


The attribute class should be pretty self explanatory. The next thing was I wanted to created a method for my attribute that would allow me to check if the attribute existed on a specific meta table and return the attribute if it did. I also wanted it to be generic, so I created an Attribute Manager class with the relevant code to return any attribute from an attribute collection, like this:

    using System;
    using System.ComponentModel;

    namespace Heathesh.Com.BusinessLogic
    {
        /// <summary>
        /// Attribute manager to read custom attributes on classes, I made this static
        /// so I could use it as an Extension method
        /// </summary>
        public static class AttributeManager
        {
            /// <summary>
            /// Gets the specified attribute from the attribute collection
            /// </summary>
            /// <param name="attributes">Extends an Attribute collection</param>
            /// <param name="attributeType">The type of attribute to check for and return if found</param>
            /// <returns></returns>
            public static Attribute GetAttribute(this AttributeCollection attributes, Type attributeType)
            {
                foreach (Attribute attribute in attributes)
                    if (attribute.GetType().Equals(attributeType))
                        return attribute;

                return null;
            }
        }
    }


I used an Extension method so I could simply extend the Attribute collection, and easily have my method available to me on any Attribute collection. So now that I have my attribute, and a manager class to return it, I needed to add my attribute to my scaffolding code to indicate that I wanted to disable insert and delete for my SiteSetup table. So I changed my SiteSetup scaffolding code to look like this:

    using System.ComponentModel.DataAnnotations; //add this using for the MetadataType attribute
    using Heathesh.Com.Entity.Attributes; //* USING TO ALLOW ME TO ACCESS MY ATTRIBUTE *

    //The namespace used here must be the same as your Entity Model namespace. The best way (if you
    //don't already know the namespace) to find out the correct namespace is to expand your .edmx file
    //and then open the Designer.cs file and you will see the namespace there
    namespace Heathesh.Com.Entity
    {
        /// <summary>
        /// Partial class of my MetaTable, using the MetadataType attribute to indicate the
        /// class I'm using to save my scaffolding info
        /// </summary>
        [MetadataType(typeof(SiteSetupMetaData))]
        [CustomBehaviour(false, false)] //* NEW ATTRIBUTE *
        public partial class SiteSetup
        {

        }

        public class SiteSetupMetaData
        {
            /// <summary>
            /// I don't want the user to see the Id field, because in this case
            /// the Id field is an int with an Indentity, so the user will never
            /// need to insert or change this
            /// </summary>
            [ScaffoldColumn(false)]
            public object Id { get; set; }
        }
    }



Looking at the code, you'll see I added the new using for the attribute, and the attribute above the "public partial class SiteSetup". Okay,  now the last thing left was to remove the insert and delete buttons on the List and Details pages of my Dynamic Data site if  the attribute was present and set appropriately. To begin with, I found my List page (DynamicData\PageTemplates\List.aspx) and opened the code behind. First to hide the insert, I added the following code at the bottom of my Page_Load:

    Attribute customBehaviour = table.Attributes.GetAttribute(typeof(CustomBehaviour));

    if (customBehaviour != null)
        InsertHyperLink.Visible = ((CustomBehaviour)customBehaviour).AllowInsert;


Next, I open my List.aspx file and added an event to the OnDataBound like so: OnDataBound="GridView1_DataBound". I then created the method in my code behind as well as a method to hide the button if required like so:

    /// <summary>
    /// Handles the grid view data bound event
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void GridView1_DataBound(object sender, EventArgs e)
    {
        Attribute customBehaviour = table.Attributes.GetAttribute(typeof(CustomBehaviour));

        if (customBehaviour != null)
            hideDeleteColumn(((CustomBehaviour)customBehaviour).AllowDelete);
    }

    /// <summary>
    /// Hides the delete column
    /// </summary>
    /// <param name="hide"></param>
    private void hideDeleteColumn(bool show)
    {
        if (!show)
            foreach (GridViewRow gridViewRow in GridView1.Rows)
                ((LinkButton)gridViewRow.Cells[0].Controls[3]).Visible = false;
    }

That took care of my List.aspx page, I next opened my Details.aspx page (DynamicData\PageTemplates\Details.aspx) and added an OnLoad event to my DetailsView1 like so: OnLoad="DetailsView1_Load". I then added the relevant code for the OnLoad method in my code behind like so:

    /// <summary>
    /// Handles the details view load
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void DetailsView1_Load(object sender, EventArgs e)
    {
        Attribute customBehaviour = table.Attributes.GetAttribute(typeof(CustomBehaviour));

        if (customBehaviour != null)
            DetailsView1.FindControl("DeleteLinkButton").Visible = ((CustomBehaviour)customBehaviour).AllowDelete;
    }


That was it, I compiled and ran the application, and insert and delete were available for all my tables except the SiteSetup table as I required.

Happy coding!

Use SSIS to run custom .Net code based on data in a table

by Heathesh 3. February 2010 00:06

The requirement was to use an SSIS package to read data from a table, and once the data had been read based on a field in the table some processing (.Net code) had to occur for each record.

This is how I went about solving the problem:

1. Create a data flow task and open it (double click it).

2. In the "Data Flow" tab add an "ADO Net Source". Setup the connection to the database and point it to the required table.

3. Next add a "Script Component" and select "Transformation" as the way the script will be used. Now connect the green arrow from "ADO Net Source" to the "Script Component". This indicates the flow of the process, and that you want the package to run the "ADO Net Source" first to retrieve the data and pass it to the "Script Component".

4. Double click the "Script Component" and select "Input Columns" on the menu on the left of the pop up window. In the screen that opens, select the relevant columns you wish to use for processing.

5. Next choose "Script" and click the “Edit Script” button at the bottom right of the window.

6. When the script opens, there should be a method called "Input0_ProcessInputRow" or something similar.

7. Within that method, you will notice that there is a Input0Buffer object being passed into the method called "Row". Using "Row" you will have access to all the columns you selected above, for example if you selected a column called "Name", you will now be able to access the column data using "Row.Name" in your script code.

8. Now add the relevant references to the script project, and code whatever you wanted to do with the records.

9. Finally, if you need to do something after this, or need to send data out from a "Script Component", select “Input and Outputs” and then expand “Output 0”. Then click on the “Add column” button and add columns and types you want to return.

10. As before in the script code the columns specified will be available in the above method using the “Row” object to access them. Using your script you can then set the values of your output columns, and they will be available to you in your next step.

Happy coding!

Good and bad exception (error) handling

by Heathesh 1. February 2010 02:36

I came across some code the other day and the person had implemented some shocking exception handling through out the application. Seeing this I thought I would touch on what I believe is good and bad practises when it comes to exception handling.

Good practises

1. Always handle errors, don't ever let an application fail and display an unhandled exception.

2. Always handle errors at the highest level possible. For example within a web application I personally add all my exception handling at either the event handler level (i.e. page_loads, button_click events) or I'll place a generic error handler in the global.asax file Application_Error event. For example:

    /// <summary>
    /// Handles any exceptions that occur in the application
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void Application_Error(object sender, EventArgs e)
    {
        //get the exception
        Exception ex = Server.GetLastError().GetBaseException();

        //log the error calling your own LogHandler class
        LogHandler.LogError(string.Format("{0}: {1}{2}{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
            System.Environment.NewLine, ex.ToString()));

        //redirect to the error page to display the error message
        Response.Redirect(HttpUtility.HtmlEncode(string.Format("/Error.aspx?ErrorMessage={0}",
            ex.Message.Replace("\r", " ").Replace("\n", " "))));
    }


3. Always log errors, and ensure that error logging can be customized. In the above example I'm calling my LogHandler.LogError method. This method should have configurable values to indicate where to log the error to, be it email, text file, log file, event log, database where ever else possible.

4. Use try finally or "using" blocks to clean up objects, you don't have to use a catch statement:

In case you are specifically using the try because you want to execute a finally, you can either use a try finally without a catch or if the object you want to clean up implements iDisposable you can use a "using":

    //use try finally without a catch
    try
    {
        //do whatever
    }
    finally
    {
        //clean up objects
    }

    //use the "using" statement
    using (MyDisposableClass obj = new MyDisposableClass())
    {
        MyDisposableClass.DoWhatever()
    } //using will always dispose of the object, whether or not there is an exception


Bad practises

1. Using try catch uneccessarily, for example:

    //bad code 1:
    try
    {
        //do what ever
    }
    catch (Exception ex)
    {
        //unless you specifically want to do something with the exception,
        //you should not be doing this
        throw ex;
    }

    //bad code 2:
    try
    {
        //do what ever
    }
    catch
    {
        //unless you specifically want to do something with the exception,
        //you should not be doing this
        throw;
    }


2. Rethrowing an exception just to add your own message to it:

    //bad code
    try
    {
        //do what ever
    }
    catch (Exception ex)
    {
        //bad bad bad
        throw string.Format("There was an error: {0}", ex.Message);
    }


3. When dealing with an exception, you should not rethrow the variable or exception object:

This time we want to catch the exception and handle it by calling our "HandleException" method, but:

    //bad code
    try
    {
        //do what ever
    }
    catch (Exception ex)
    {
        HandleException(ex);
        //if we throw the "ex", we change the line number etc. in the stack
        //trace and the application thinks the error originated here, bad
        //for debugging
        throw ex;
    }

    //good code
    try
    {
        //do what ever
    }
    catch (Exception ex)
    {
        HandleException(ex);
        //by throwing the exception without specifying the "ex",
        //we will get the correct line etc. in the stack trace indicating
        //exactly where the error occurred
        throw;
    }

   
4. Throwing exceptions for validation errors. Just don't do it.

Final thoughts


1. When dealing with exceptions always remember that exceptions bubble up. This means that no matter how deep inside your application your exception happens, if you implement your exception handling at the highest level the exception will bubble up to the top.

2. Exceptions are resource intensive, where possible never purposely throw an exception, rather use boolean methods for validation etc. and return text messages that can be displayed to the user.

Happy coding!

Tags: , , , , ,

Development | .Net



Powered by BlogEngine.NET 1.5.0.7 (with enhancements by Heathesh)
Theme by Mads Kristensen (with tweeks by Heathesh)

Certifications

Microsoft Certified Professional

Microsoft Certified Technology Specialist

Answer Questions

 

Tag cloud

Calendar

<<  September 2017  >>
MoTuWeThFrSaSu
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

View posts in large calendar

http://heathesh.com