Serializing A DataSet With DateTime Columns

by Scosby Friday, March 1, 2013

The Database

I was recently working on a legacy web service that returns a DataSet. Sometimes, these DataSets include DateTime columns with values that come from a database (Figure 1). On the client, it was confusing to see time zone offsets that were not in the database values. The clients could be in different time zones than the web server, so this behavior was easily overlooked during development.

Figure 1 –A Date Value Record

The DataSet

I wondered where the offsets were being added (Figure 2). Clearly, they weren't part of the database. I discovered they are created by the DataSet based on the time zone of the computer where it is serialized. This happens automatically when the web service returns a DataSet to the client. It also happens if you call the DataSet.GetXml method. In either case, 2003-04-06T00:00:00 was becoming 2003-04-06T00:00:00-05:00 and creating the confusion (albeit a different instance in time!).

Figure 2 - DataSet XML With An Offset

I needed to find a way to control how the DataSet was serializing its DateTime columns. After visualizing one of the DataSets (Figure 3), I noticed a property on the DataColumn called DateTimeMode. All of the columns had this property, even the columns that were not DateTime columns. I noticed they were all set to UnspecifiedLocal and decided to investigate.

Figure 3 – Visualizing Columns In A DataSet

 

The Server-Side Fix

Usually, it is not possible to change the DateTimeMode of a column once a DataSet has rows. However, it is possible to change the mode between UnspecifiedLocal and Unspecified because that only affects serialization and not the actual value. This is exactly what I needed and so I wrote the following code on the server side:

System.Data.DataSet data = new DataSet();

 

// ...

 

// Iterate the columns and set DataColumn.DateTimeMode

// to DataSetDateTime.Unspecified to remove offset

// when serialized.

foreach (DataTable table in data.Tables)

{

    foreach (DataColumn item in table.Columns)

    {

        // Switching from UnspecifiedLocal to Unspecified

        // is allowed even after the DataSet has rows.

        if (item.DataType == typeof(DateTime) &&

            item.DateTimeMode == DataSetDateTime.UnspecifiedLocal)

        {

            item.DateTimeMode = DataSetDateTime.Unspecified;

        }

    }

}

This code is pretty straight forward. Changing the column’s mode to Unspecified results in a DateTime value with no offset. This value now matches the database record exactly. This leaves the problem of formatting the value for display completely up to the client-side application.

Figure 4 - DataSet XML With No Offset

Summary

This post discussed how to control the formatting of DateTime columns when a DataSet is serialized. I showed an example of the default behavior which includes the time zone information offset. Finally, I showed a code snippet that changes the behavior to exclude the offset.

Tags: , , ,

IT | Programming

Detecting SharePoint Forms Services

by Scosby Friday, September 30, 2011

Introduction

The reader will learn how to use the Forms Services Feature Detection Protocol. The solution demonstrated will post a HTTP request to a SharePoint detector page without calling a SharePoint web service. This approach allows even a SharePoint Reader to use the Forms Services Feature Detection Protocol. Future posts about Forms Server will utilize the solution presented in this post.

InfoPath In SharePoint

InfoPath Forms Services, included with Microsoft SharePoint Server 2010, provides a Web browser experience for filling out InfoPath forms. InfoPath 2010 integrates with SharePoint’s Business Connectivity Services (BCS) enabling users to connect their organization's forms to important business data that is stored in external line-of-business systems such as SAP, Oracle or even Twitter! Read the InfoPath Forms Services Overview for more information.

Forms Server Detector

Using the Forms Services Feature Detection Protocol, the reader can easily detect if Forms Server exists and is enabled on a specific site. By posting a query string to the FormServerDetector.aspx page, a response of HTTP No Content 204 will be returned if the request was successful but Forms Server features are not enabled, and a HTTP OK 200 if Forms Server features are enabled. If Forms Server is enabled, the response body contains the detection result but it should always be true according to the protocol.

Solution

The solution first constructs the detector URI from the following parts: the site URL, the FormServerDetector.aspx page and the protocol query parameter. Using the detector URI, the solution posts an HTTP request and inspects the HTTP response to detect the Forms Server status for the site. The protocol specifies the client request headers should include an Accept header with */* as the value. If Forms Server is enabled, the response body will contain the following text:

<server IsFormServerEnabled = 'true' />

Code Sample


        public static bool IsFormsSevicesEnabled()

        {

            UriBuilder builder = new UriBuilder("http://scvm1");

            builder.Path = "/_layouts/FormServerDetector.aspx";

            builder.Query = "IsFormServerEnabled=check";

 

            string servicePath = builder.Uri.GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);

 

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(servicePath);

            request.Accept = "*/*";

            request.UseDefaultCredentials = true;

 

            HttpWebResponse response = null;

 

            try

            {

                response = (HttpWebResponse)request.GetResponse();

            }

            catch (WebException ex)

            {

                response = (HttpWebResponse)ex.Response;

            }

 

            if (response.StatusCode == HttpStatusCode.OK)

            {

                using (System.IO.StreamReader sr = new StreamReader(response.GetResponseStream()))

                {

                    System.Xml.Linq.XElement doc = XElement.Parse(sr.ReadToEnd());

 

                    XAttribute fsAttribute = doc.Attribute("IsFormServerEnabled");

 

                    return bool.Parse(fsAttribute.Value);

                }

            }

 

            return false;

        }

The reader should take note of the protocol query parameter assigned to the builder.Query property. By using a value of “check” for the detection protocol query parameter, the request will be processed by the protocol server. This solution provides broad support for remote clients to detect Forms Server capabilities, but without resorting to checking for SharePoint Feature definitions.

More Information

·         InfoPath Forms Services Overview

·         Forms Services Feature Detection Protocol Specification [MS-FSFDP]

·         Request for Forms Server Detection

Tags: ,

IT | Programming

Website Updates

by Scosby Friday, May 28, 2010

I finally added paging to the albums and photos pages. Much better. Additionally, I locked down the registration page with recaptcha. The albums are now sorted in descending order, so the newest ones will show up first. More tweaks coming! Time for bed.

-Scosby

Tags: ,

IT | Programming

Another blog update - custom themes and code changes!

by Scosby Wednesday, May 19, 2010

I created a new theme for the standard and mobile styles. Basically, I copied the original ones and fixed the gross parts. Additionally, I made some minor code changes to a couple of pieces, all good and very subtle. I'll be posting my new themes along with a change log for the source if I get around to it. In the meantime, enjoy!

Tags: , ,

IT | Programming

Hitting a web page programmatically

by Scosby Tuesday, January 19, 2010

Let's say you have a friend who is trying to win a popularity contest on a local web site. Furthermore, let's say that after you go to the site and vote you notice there is no login required and you see a bunch of crap in the query string for links as you hover over them. Let's go a step further and say you decide to write a program that will hit the website and perform the vote automatically. So, let's look at the classes in the .NET Framework that will help you do this simple example.

You will need to make a HttpWebRequest. This class allows you to work directly with a web server via HTTP and get a response back from it. To get a HttpWebResponse, we create a request and then get a response back. Quite simple, really.

Let's look at some code now.

HttpWebResponse response = null; 

try
{   
     HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(site);

     req.UserAgent = @"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0)";
    

     response = (HttpWebResponse)req.GetResponse();
    

     String
message = "Http response code " + ((Int32)response.StatusCode).ToString() + " :: " + Enum.GetName(typeof(HttpStatusCode), response.StatusCode);
    

     this
.UpdateTextBox(message);
}
finally
{   
     response.Close();

}

Let's break a couple of lines down and look at them in more depth. The first line we'll look at creates our web request:

HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(http://www.webserver.com/View.aspx?ID=134684&R=10);

Here, the static Create method on the HttpWebRequest class returns as an instance of the abstract base class WebRequest, so we must cast it back to a HttpWebRequest. We pass in the full URL to the Create method, this includes any query string parameters that you need.

In the next line we'll look at you'll see how we actually hit the server:

response = (HttpWebResponse)req.GetResponse();

Here, the GetResponse method on the HttpWebRequest class returns the response from the web server. Note, similar to the HttpWebRequest.Create method we need to cast the WebResponse return value to a HttpWebResponse. We can then use the StatusCode property to determine the results of our operation. I store this information in a variable named "message", which is then passed off to a contrived example method to perform further processing in this example.

The last step you should take is to release the the connection for reuse by other requests, you accomplish this by calling the HttpWebResponse.Close method.

This is a simple, abeit trivial, example of how you can work with web servers in code and help your friends win contests. This could easily be extended and plugged into a windows service, with a config file for the site and various other options...maybe even a winforms configuration application. Sounds like a good homework project to me ;)

-Scosby

Tags: , ,

Technology | Programming

Visual Studio 2010 Web Deployment Rocks!

by Scosby Wednesday, December 2, 2009

There is a new feature in VS10 that is going to rock! I'm talking about Web.Config Transforms. While, admittedly, this functionality was provided by the VS9 web deployment project's web.config section replacement, I'm really excited to see the idea incorporated directly into the RTM and even improved!

http://blogs.msdn.com/webdevtools/archive/2009/05/04/web-deployment-web-config-transformation.aspx

In a nutshell, VS10 will let you define "XML Document Transforms" (xdt's) in your source web.config that will take appropriate action based on your web.config transform files. So you could replace, insert, or even remove certain sections, depending on your transform file. Really cool!

Tags: , ,

IT | Programming

Switching between ASP.NET application services providers at runtime.

by Scosby Wednesday, April 15, 2009

I had to spend a little time thinking about this one tonight, so here it is for you to digest!

Let's say you have a web app that utilizes the ASP.NET Role provider and Membership provider. Specifically, we'll focus on the SQL providers (SqlRoleProvider and SqlMembershipProvider). It is easy enough to wire these providers up in your web.config and get things running quickly (yay for agility *cough*). Visit either link for the SQL provider classes mentioned above for a sample web.config from MSDN if you're still wondering.

Consider the following: what if I want to set up "test" or "staging" environment providers in the web.config and have the web app use the "test" provider instead of the default (production) provider during testing? In my case, I wanted to use different databases, but this could easily happen to you should you wish to use a completely different provider depending on a condition (for instance, a query string parameter might indicate you should use an Active Directory or Oracle provider, ect).

At first, I thought I could simply change the application's provider at runtime but it became obvious to me, eventually ;), that it wasn't going to work. Instead, I created a static ProviderManager class which returns a cached instance of a Role or Membership provider. It was a pity to say goodbye to the Roles and Membership classes, but alas, I now delegate them to my ProviderManager class' method when I want to work with either provider. This ProviderManager class makes it possible for me to cache the desired provider from the web.config based on any criteria of my choosing. In my case, I simply choose to use the DEBUG constant with compiler directives to return my "test" or "staging" providers (only when debugging, obviously). You certainly could make it more complicated and work with any number of conditions, such as multiple connection strings and/or providers. Enjoy!

public static class ProviderManager
{
     private static MembershipProvider membershipProvider;

       .....

     public static MembershipProvider GetMembershipProvider()
     {
          if (ProviderManager.membershipProvider == null)
          {
               //Get the default provider
               MembershipProvider provider = Membership.Providers["ScosbyMembershipProvider"];
#if DEBUG
          provider = Membership.Providers["TestMembershipProvider"];
#endif
               ProviderManager.membershipProvider = provider;
          } 
               return ProviderManager.membershipProvider;
     }

      ..... 

}

Thus, instead of writing code such as: Roles.CreateRole("WidgetTechs");

We write code to use the new ProviderManager class: ProviderManager.GetRoleProvider().CreateRole("WidgetTechs");

Tags: ,

Technology | Programming

Silverlight 2 and cross-browser compatibility when using HtmlTextWriter

by Scosby Tuesday, February 3, 2009

If you are using a custom ASP.NET web control to render your Silverlight 2 Object tag with the HtmlTextWriter, you need to make sure to render the Object tag's param elements as self-closing. Otherwise, you will discover that IE 6, 7, and 8 will ignore the invalid XHTML 1.0 Transitional "</param>" element and load the Object tag (meaning your Silverlight app) correctly but Google Chrome and Mozilla Firefox will not.

Instead, you should render your param elements as self-closing by using the HtmlTextWriter's WriteBeginTag method and the SelfClosingTagEnd constant. According to MSDN's WriteBeginTag documentation, "the WriteBeginTag method does not write the closing angle bracket (>) of the markup element's opening tag. This allows the writing of markup attributes to the opening tag of the element." This means you can close it yourself with the SelfClosingTagEnd constant, which they do not demonstrate but is easily to accomplish and removes the need to call WriteEndTag in their example.

This behavior can be verified easily. If you remove the self-closing tag from a Visual Studio Silverlight Web's *.html test page and add the explictly closed element, the behavior will manifest itself.

PS - Chrome and Firefox will also not load the Object tag if you provide a param element with an empty value. For example: <param name="onerror" value="" />

Tags: , , , ,

Technology | Programming