Thursday, 26 July 2012

ObjectDataSource Ignores Culture Information When Updating

"When using a business object with the ObjectDataSource control, culture information seems to be ignored when property values are extracted from the TextBox control generated by a BoundField. The same is true when a TemplateField is used." from here.
And, yes it is true. I encountered this problem when I was working on a page using FormView and ObjectDataSource to grab some values including a date value into the database. I used jQuery Datepicker to tie it to my date text box and because the website will be used in Australia, then I changed the date format of Datepicker to Australian format which is dd/MM/yyyy (in .NET) like this:


<script type="text/javascript">
    $(document).ready(function () {
        $('#DateTextBoxID').datepicker({ dateFormat: "dd/mm/yy" });
    });
</script>

Then, happily added below setting to my web.config file to change the culture to en-AU.


    <globalization culture="en-AU" uiCulture="en-AU"/>

When, I clicked the update button of my FormView I got error.

The problem was that my entered value for the date field was 27/07/2012 and if you pars it in US date formatting which is (MM/dd/yyyy) of course we don't have 27th month! If I had entered 12/07/2012 then everything seems working except that the date was wrong into the database.
Ok, this was the problem and you can find some workarounds for this "bug" at above link under Workarounds tab. I chose to add update and insert parameters for that date field to my ObjectDataSource as below:


    <InsertParameters>
        <asp:Parameter Name="DateField" Type="DateTime" />
    </InsertParameters>
    <UpdateParameters>
        <asp:Parameter Name="DateField" Type="DateTime" />
    </UpdateParameters>


By adding these parameters, ObjectDataSource will use your globalization settings and it did the job for me.

Happy Globalization!

Thursday, 5 July 2012

How I Modernized My Error Logging by ELMAH

In one of my ASP.NET applications, I didn't have enough time to add a better error logging mechanism, so I ended up with this:

protected void Application_Error(object sender, EventArgs e)
{
    IPrincipal principal = Thread.CurrentPrincipal;
    var err = "Error Caught in MyApplication\n" +
            "Error in: " + Request.Url +
            "\r\nUsername: " + principal.Identity.Name +
            "\r\nError Message:" + objErr.Message +
            "\r\nStack Trace:" + objErr.StackTrace;
    SendMail(
        "from@example.com",
        "to@example.com",
        String.Format("Exception @{0}"DateTime.Now),
        err);
}

And of course having my custom error settings and pages in the web.config:
      <customErrors defaultRedirect="GenericErrorPage.aspx"
        mode="RemoteOnly" xdt:Transform="Replace">
        <error statusCode="404" redirect="FileNotFound.aspx" />
      </customErrors>

Actually, it did the job for me and I was receiving emails from the above code into my inbox whenever there was any unhandled exception in that application. The problem with this approach is that it is not configurable and I was receiving so many emails into my inbox even for 404 error code which is Http file not found error. In addition, I needed to store the exceptions somewhere i.e. in a database easy and without any coding, so I will be able to generate some reports out of it later.

ELMAH

ELMAH (Error Logging Modules and Handlers for ASP.NET) is the right and fast answer for this need. Actually, it has been there for years. First, you need to install ELMAH into your web project from nuget running this command in your Package Manager Console in Visual Studio:
Install-Package elmah

This command will do almost everything for you specially your web.config settings. To test it, just point to below URL to generate a test exception in your web application.
http://YourLocalWebSiteUrl/elmah.axd/test

Then point to http://YourLocalwebSiteUrl/elmah.axd to see the ELMAH output.

If you can see ELMAH output, then it is working for your in-memory logs. Now, you need to make it to store logs into your SQL Server database (or any other db that it supports). To set up ELMAH to save logs to SQL Server, you need to create the error log source data table and stored procedures in your database by 
running a DBML script from:
http://code.google.com/p/elmah/downloads/detail?name=ELMAH-1.2-db-SQLServer.sql

The web.config settings for database logging is:

<errorLog type="Elmah.SqlErrorLog, Elmah" 
          applicationName="YourApp"
          connectionStringName="YourConnectionStringName" />

Notice to the applicationName property in above settings which is useful when you are using a centralized database to log errors for all of your web applications.To add email notifications all you need is:
 <errorMail from="from@example.com"
            to="to@example.com"
            subject="Unhandled Exception in My Application"
            priority="High"
            async="true"
            smtpPort="25"
            smtpServer="YourSMTPServer"
            useSsl="false"
            noYsod="false" />

If you want to filter some errors like 404 error, so ELMAH won't log them or send email then:

<errorFilter>
  <test>
    <or>
      <and>
        <equal binding="HttpStatusCode" value="404" type="Int32" />
      </and>
    </or>
  </test>
</errorFilter>    

If you want ELMAH to log 404 errors, but does not send emails for this type of error:
<errorFilter>
  <test>
    <or>
      <and>
        <equal binding="HttpStatusCode" value="404" type="Int32" />
        <regex binding="FilterSourceType.Name" pattern="ErrorMailModule" />
      </and>
    </or>
  </test>
</errorFilter>

Resources

Tuesday, 3 July 2012

ASP.NET MVC and SSRS Reports

To display a SQL Server Report (SSRS) into your website, you will need a ReportViewer server control which belongs to ASP.NET Web Forms world and not ASP.NET MVC. So how can you have a SSRS report into your ASP.NET MVC application? It is easy and thanks to the side-by-side running of these two different worlds!

First, you need a normal Web Form page in your MVC application to put the ReportViewer server control into it. I would create a Reports folder in the root of my MVC application and then add a Web Form called ReportViwer.aspx into it.

Then, drag a ReportViewer server control from the Reports Toolbox into the page.

<%@ Page Language="C#" AutoEventWireup="true"  MasterPageFile="~/Site.Master" CodeBehind="ReportViewer.aspx.cs" Inherits="YourWebsite.Reports.ReportViewer" %>
<%@ Register assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" namespace="Microsoft.Reporting.WebForms" tagprefix="rsweb" %>
 
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <rsweb:ReportViewer ID="ReportViewer1" runat="server" Height="800px" 
            ProcessingMode="Remote" Width="100%" Font-Names="Verdana" Font-Size="8pt" 
                InteractiveDeviceInfos="(Collection)" WaitMessageFont-Names="Verdana" 
                WaitMessageFont-Size="14pt">
        </rsweb:ReportViewer>
</asp:Content>

Next, you need to add a new route to your routing configuration in the Global.asax.

public static void RegisterRoutes(RouteCollection routes)
{
    // Your other route settings
    // ...
 
    routes.MapPageRoute(
        "reports_browse",
        "Report/{reportName}.aspx",
        "~/Reports/ReportViewer.aspx"
        );
 
    // Your other route settings
    // ...
}
In this route, notice to the {reportName} placeholder which will be your actual SSRS report name (reportName.rdl). Here, all we are doing is to send all http://YourApp/Reports/reportName.aspx to the single page ReportViewer.aspx in the Reports folder that we discussed above.
The last step is to read the report name from the route data in ReportViewer.aspx page and set your ReportViewer server control to point to your report on the report server.

protected void Page_Load(object sender, EventArgs e)
{
    string reportName = Page.RouteData.Values["reportName"as string;
    ReportViewer1.ServerReport.ReportPath = String.Format("YourReportsPath/{0}.rdl", reportName);
}

Happy reporting!

Monday, 2 July 2012

DDD! Sydney 2012

Last weekend, I had a chance to attend DDD! Sydeny 2012. I was there to see some names in person and to see what is hot in the market this year. It was a good conference, but it could be better with better subjects and better organization. I attended these sessions:

Node.js - is that it? - confused!

ASP.Net Web API - From Web to REST in 60 minutes - good

Automated UI testing done right! - interesting - well done Mehdi!

Shiny! Shiny! Shiny! All the new newness in Visual Studio 2012 - really enjoyed!

LESS CSS for .NET developers - not really interested

Event Sourcing & DDD: A Love Story - I left this session to the next one!

HTML 5 and the Mobile Web - Do you really need an app? - good for HTML5 lovers!

Tuesday, 26 June 2012

Back to the Community...

Simple and straightforward, I just decided to back to the community after years, this time of course, in English.

Will back soon with new posts.