Denny.NET

I can haz ASP.NET goodness?

About the author

Denny Ferrassoli
Developer at Casting Networks. MCP / .NET
E-mail me Send mail
Add to Technorati Favorites

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008

Entity Framework (EF) and Lazy Loading

I came across a great article today that explains a little about Entity Framework's (EF) default lazy load settings. At first you may be confused as to why they decided to default to lazy loading relationship objects but if you take a good look it makes sense.

The team behind EF didn't want this *automatic* behavior happening. The reason behind this decision is simple: When architecting a larger project, it is highly important for developers to clearly understand when they are accessing certain resources, such as the database.

You can run into a boat-load of performance/scalability issues if you are not aware of what relationships are being loaded using LINQ to SQL. EF tries to eliminate this issue by defaulting to lazy loading. Read the article for a great example and explanation.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | Server-Side
Posted by Denny on Monday, April 28, 2008 2:07 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Passing a JSON object to a WCF service with jQuery

[Updated: 04/25/08] 

This example uses WCF to create a service endpoint that will be accessible via an ASP.NET page with jQuery/AJAX. We will use AJAX to pass a JSON object from the client-side to the webservice. We will only use jQuery to connect to the web service, there will be no ASP.NET AJAX library used. Why no ASP.NET AJAX library? jQuery is already included in the project and it can handle all the necessary AJAX calls and functionality that we would want if we were using the ASP.NET AJAX script library. We're also going to save  about 80kb of overhead (much more if in debug mode) by excluding the ASP.NET AJAX library. This is in no way saying that the ASP.NET AJAX library isn't useful... As a matter of fact if we were to do the same example with the library we could save ourselves from writing extra code. However the point of this example is to show that we can access the web service even if we don't have a nicely generated client-side proxy a la ASP.NET AJAX.

The WCF Service:

I'm going to start by adding an AJAX-enabled WCF Service to a Website. (Make sure you're running the correct version of .NET - I am using 3.5 here)

After adding the service it opens up to the service's code-behind file. Go ahead and browse around the file for a second.

The first thing I'm going to point out is to make sure that the "AspNetCompatibilityRequirements" is set to "Allowed":

[code:c#]
[AspNetCompatibilityRequirements( RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed )]
[/code]

This attribute indicates that our service should run in ASP.NET compatibility mode. If it were not "Allowed" we would not be able to access the service from ASP.NET. This attribute is automatically generated when you add the "AJAX-enabled WCF Service." For a detailed explanation of the attribute go to MSDN.

Looking at the generated code-behind file we can see it has placed a "DoWork()" method with the "OperationContract" attribute. This is created by default but lets keep it since we will be using this method to run this example. One thing we want to add is a "WebGet" attribute and set the "RequestFormat" to "Json." WebGet associates the operation with a UriTemplate (not discussed in this example) as well as the GET verb. Setting the RequestFormat allows us to define that the Request should be in JSON format. Our "DoWork()" method should now look like this:

[code:c#]
[OperationContract]
[WebGet( RequestFormat=WebMessageFormat.Json )]
public void DoWork()
{
 // Add your operation implementation here
 return;
}
[/code]



The Data/Object Structure:

We want to pass in a "Person" object to the "DoWork()" method so lets quickly create a Person object with properties for a Name, Age and the types of Shoes they own (first thing that popped into my head). This class will also serve as the structure for our JSON object.

[code:c#]
[Serializable]
[DataContract( Namespace = "http://www.dennydotnet.com/", Name = "Person" )]
public class Person
{
 private string _name = string.Empty;
 private int _age = 0;

 [DataMember( IsRequired = true, Name = "Name" )]
 public string Name
 {
  get { return _name; }
  set { _name = value; }
 }

 [DataMember( IsRequired = true, Name = "Age" )]
 public int Age
 {
  get { return _age; }
  set { _age = value; }
 }

 [DataMember( IsRequired = true, Name = "Shoes" )]
 public List<String> Shoes;

}
[/code]

We've decorated our Person class as a DataContract specifying the Namespace and Name. We've also decorated our properties with a DataMember attribute. We've set "IsRequired" for each one to true and specified the Name. You really only need to specify the "Name" if it's going to be different than the property name. For example you could have a property named "Level" and the DataMember attribute's Name set to "Rank." We can now go back and modify our "DoWork()" method to receive a Person object as a param. It should now look like the following:

[code:c#]
[OperationContract]
[WebGet( RequestFormat=WebMessageFormat.Json )]
public void DoWork(Person p)
{
 // Add your operation implementation here
 return;
}
[/code]

The Web.Config File:

You'll need to make a few changes to your web.config file before you can access your service. You'll need to add a serviceBehavior to allow httpGet and we'll also add some helpful debugging options too. Add the following to your web.config:

Below </endpointBehaviors>

[code:xml]
<serviceBehaviors>
 <behavior name="ServiceAspNetAjaxBehavior">
  <serviceMetadata httpGetEnabled="true" httpGetUrl="" />
  <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
 </behavior>
</serviceBehaviors>
[/code]


Between <services>[here]</services> your service node should look like this:
[code:xml]
<service name="Service" behaviorConfiguration="ServiceAspNetAjaxBehavior">
 <endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior"
  binding="webHttpBinding" contract="Service" />
 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
[/code]

A security note about the following line:

[code:xml]
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
[/code]


Allowing exception details can expose internal application information including personally identifiable or otherwise sensitive information. Setting the option to true is only recommended as a way to temporarily debug your service!!

Your Web.Config should look like the following: (pardon the colors)

The Front-End:

Now that the service is created and configured we can move to the front-end (make sure jQuery.js is included in your ASP.NET page). First let's create a sample JSON object that we will pass to the service. We'll create the JSON object based on the structure of the Person class.

[code:js]
var mydata = { "Name":"Denny", "Age":23, "Shoes":["Nike","Osiris","Etnies"] };
[/code]


If you're not too familiar with JSON this is what our JSON object looks like as an object (JsonViewer):

We need to somehow communicate with the WCF service and since we're using jQuery we can use the library's built-in AJAX methods. The code below creates an AJAX call. the headers are set to GET and the contentType is application/json. We set the url to the path to our WCF service's svc file with a trailing / and then the name of the method we want to execute. In this case we're calling the "DoWork()" method. "data" will be passed in to our function and processData should be set to false so that jquery does not try to auto-process our data. We've also added a success and error function to let us know what happens after executing the AJAX.

[code:js]
function sendAJAX(data) {
 $.ajax({
  type: "GET",
  contentType: "application/json",
  url: "Service.svc/DoWork",
  data: data,
  processData: false,
  success:
   function(msg){
     alert( "Data Saved!" );
   },
  error:
   function(XMLHttpRequest, textStatus, errorThrown){
       alert( "Error Occured!" );
   }
 });
}
[/code]

Now unfortunately there is a small issue here. We must send the actual JSON string as the value for DoWork's Person p param and there's no easy way of turning your JSON object into a string. If you try "data.toString()" you'll just get an "[object Object]" value (remind you of anything?), which is not what we want. So here's a slightly modified function that will take your JSON and turn it into a string.

Note* The JSON de/serialization handles Date/Time in a specific way. The json2string function below does not take this into account. I'm sure there are some implementations out there which will work with ASP.NET AJAX but this one does not. For more information on this you can go here.

Update [4/11/08]: The javascript below has a few issues so it's been suggested that you should use the JSON.org version to "stringify" your object. You can download the script from here.

Update [4/25/08]: Rick Strahl has modified the JSON.org script so that it will properly create the dates to work with ASP.NET AJAX (read his post)

[code:js]
function json2string(strObject) {
 var c, i, l, s = '', v, p;

 switch (typeof strObject) {
 case 'object':
  if (strObject) {
   if (strObject.length && typeof strObject.length == 'number') {
    for (i = 0; i < strObject.length; ++i) {
     v = json2string(strObject[i]);
     if (s) {
      s += ',';
     }
     s += v;
    }
    return '[' + s + ']';
   } else if (typeof strObject.toString != 'undefined') {
    for (i in strObject) {
     v = strObject[i];
     if (typeof v != 'undefined' && typeof v != 'function') {
      v = json2string(v);
      if (s) {
       s += ',';
      }
      s += json2string(i) + ':' + v;
     }
    }
    return '{' + s + '}';
   }
  }
  return 'null';
 case 'number':
  return isFinite(strObject) ? String(strObject) : 'null';
 case 'string':
  l = strObject.length;
  s = '"';
  for (i = 0; i < l; i += 1) {
   c = strObject.charAt(i);
   if (c >= ' ') {
    if (c == '\\' || c == '"') {
     s += '\\';
    }
    s += c;
   } else {
    switch (c) {
     case '\b':
      s += '\\b';
      break;
     case '\f':
      s += '\\f';
      break;
     case '\n':
      s += '\\n';
      break;
     case '\r':
      s += '\\r';
      break;
     case '\t':
      s += '\\t';
      break;
     default:
      c = c.charCodeAt();
      s += '\\u00' + Math.floor(c / 16).toString(16) +
       (c % 16).toString(16);
    }
   }
  }
  return s + '"';
 case 'boolean':
  return String(strObject);
 default:
  return 'null';
 }
}
[/code]

Now that we have a function to turn our JSON object into a string we need to go back and update the "mydata" variable that we defined above. After applying the json2string function we should have the following: 

[code:js]
var mydata = { "Name":"Denny", "Age":23, "Shoes":["Nike","Osiris","Etnies"] };
var jsonStr = "p=" + json2string(mydata);
[/code]

Notice that I prepended the "p=" string to our json string. "p" matches the parameter name in our "DoWork()" method. So if our parameter name was "Dude" ( i.e. DoWork(Person Dude) ) then we would use "Dude=" instead.

Now that we've built the querystring to the web service we can see what our call is going to look like:

http://www.dennydotnet.com/Service.svc/DoWork/?p={ "Name":"Denny", "Age":23, "Shoes":["Nike","Osiris","Etnies"] }

You may get a URL Encoded value too, which would look like:

http://www.dennydotnet.com/Service.svc/DoWork/?p=%7b+%22Name%22%3a%22Denny%22%2c+%22Age%22%3a23%2c+%22Shoes%22%3a%5b%22Nike%22%2c%22Osiris%22%2c%22Etnies%22%5d+%7d%3b

Go ahead and link "jsonStr" to the "SendAjax()" javascript method so we can debug our service and verify that the data was passed through to the service... check it out:

And now you just need to implement your logic in the DoWork() method. Notice how you don't have to do any de/serialization on the WCF service side either, it's already done for you. Now you should certainly implement some exception management so that you don't get any invalid data, or even add some authentication, but I'll leave that up to you...

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,
Posted by Denny on Monday, March 03, 2008 2:40 PM
Permalink | Comments (5) | Post RSSRSS comment feed

Execute a Delegate with a Timeout

Was browsing through Gustavo Duarte's "Lock Down SQL Server 2005" blog and came across a link for "Generic C# code for executing a delegate with a timeout."

It's a very useful snippet of code and reuseable.

Here's the method signature: 

[code:c#]
ExecuteWithTimeout<T>(this Func<T> delegateToRun, TimeSpan timeout)
[/code]

If the execution takes longer than timeout a TimeoutException will occur.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | Server-Side
Posted by Denny on Wednesday, February 13, 2008 1:44 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Generating a Case Statement in LINQ to SQL

LINQ is so much fun and makes things so much easier to accomplish. It's also gaining quite a bit of acceptance and it's evolving too with things like: LINQ to JavaScript and LINQ to JSON. I've been playing with LINQ quite a bit and recently I needed to generate a CASE statement with LINQ to SQL. It was fairly easy to accomplish since LINQ is so darn cool! Here is what I came up with:

[code:c#]
var gimmeh_gimmeh =
 from t in db.sc_Timeslots
 where (t.starttime.Minute % 5 == 0) || (t.starttime.Minute % 10 == 0)
 select new
 {
  t.id,
  t.starttime,
  interval = (t.starttime.Minute % 5 == 0) ? "5 Minutes" : "10 Minutes"
 };
[/code]

The line: "interval = ..." generates a CASE statement as shown below.

[code:tsql]
SELECT [t0].[id], [t0].[starttime],
    (CASE
        WHEN (DATEPART(Minute, [t0].[starttime]) % @p4) = @p5 THEN CONVERT(NVarChar(10),@p6)
        ELSE @p7
     END) AS [interval]
FROM [dbo].[sc_Timeslot] AS [t0]
WHERE ((DATEPART(Minute, [t0].[starttime]) % @p0) = @p1) OR ((DATEPART(Minute, [t0].[starttime]) % @p2) = @p3)
[/code]

You can have multiple CASE statements or even concat them like so:

[code:c#]
  interval = ((t.starttime.Minute % 5 == 0) ? "5 Minutes" : "10 Minutes") + ((t.id == 1) ? " (Master ID)" : "")
[/code]

Which will generate the Case statement below (hey I'm starting to rhyme):

[code:tsql]
    (CASE
        WHEN (DATEPART(Minute, [t0].[starttime]) % @p4) = @p5 THEN CONVERT(NVarChar(22),@p6)
        ELSE @p7 + (
            (CASE
                WHEN [t0].[id] = @p8 THEN @p9
                ELSE CONVERT(NVarChar(12),@p10)
             END))
     END) AS [interval]
[/code]

You can also nest the CASE statements... but I think by now you're clever enough to figure that out on your own.

Enjoy!

kick it on DotNetKicks.com
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,
Categories: ASP.NET | Server-Side
Posted by Denny on Friday, February 08, 2008 10:04 AM
Permalink | Comments (0) | Post RSSRSS comment feed

LINQ to SQL: LoadFromPost

Holy rectal regions... This has been a crazy two weeks. Yes my site was down and yes it's finally back up now (have you noticed yet?). I have been quite busy lately - I moved my blog, as well as a few other sites, onto a Virtual Private Server (on AppliedI.net - they really kick ass) you can get free setup by using the coupon code: ZILCH.

Anyways... I'm happy to announce I won the LinqDev.com contest with my LINQ to XML RSS reader code (I'll post that later). I received a copy of HALO 3 Legendary Edition as well as 3 Apress books (really cool!). Big thanks to Joseph C. Rattz Jr. the author of "Pro LINQ: Language Integrated Query in C# 2008" (Amazon). If you're interested in LINQ get this book, seriously.

So anyways, I've been playing with LINQ and loving it! I was playing with a sample form I generated a while back and got caught up writing a LoadFromPost<t> function. For any of you who have ever used SubSonic you're probably aware of the LoadFromPost method. I decided to try and port it to LINQ to SQL (kinda) as well as play with Reflection since I have never really dipped into it before. Is it a good peice of code? I don't know... performance...? I don't know... I built it just to see what I could do with LINQ and Reflection... Nifty at best ;) If you have any comments, suggestions, fixes, tweaks, ideas, etc... feel free to post a comment.

LoadFromPost basically looks at your Request.Form collection and tries to match up any field names with the corresponding name in the <t> object. Only puplic properties are searched and of course you cannot set an EntitySet type so those are also avoided.

I did have to borrow some code from Peter Johnson (link in the code) to get this working properly. The problem is that Convert.ChangeType does not work with nullable types. Peter's code allows converting of nullable types, this makes it worth it even if you don't like the LoadFromPost method.

[code:c#]
 public t LoadFromPost<t>( bool catchException )
 {
  NameValueCollection formPost = HttpContext.Current.Request.Form;

  // Create new instance of t type
  t obj = Activator.CreateInstance<t>();

  // Filter: do not include any EntitySet properties
  IEnumerable<PropertyInfo> pic = obj.GetType().GetProperties().Where( p => !p.PropertyType.Name.Contains( "EntitySet" ) );

  // Iterate through valid properties
  foreach( PropertyInfo pi in pic ) {
   string propname = pi.Name.ToLower();
   bool matchFound = false;

   // Iterate through form values
   foreach( string s in formPost.AllKeys ) {
    if( matchFound ) break;

    string formname = s.ToLower();

    if( formname.EndsWith( "_" + propname ) || formname.EndsWith( "$" + propname ) || formname.Equals( propname ) ) {
     // Match - set value
     string fval = (formPost[s].Length == 0) ? null : formPost[s];
     matchFound = true;

     try {
      pi.SetValue( obj, ChangeType( fval, pi.PropertyType ), null );
     } catch( Exception ex ) {
      if( catchException ) throw ex;
     }
    }
   }
  }

  return obj;
 }

 /// <summary>
 /// Returns an Object with the specified Type and whose value is equivalent to the specified object.
 /// </summary>
 /// <param name="value">An Object that implements the IConvertible interface.</param>
 /// <param name="conversionType">The Type to which value is to be converted.</param>
 /// <returns>An object whose Type is conversionType (or conversionType's underlying type if conversionType
 /// is Nullable&lt;&gt;) and whose value is equivalent to value. -or- a null reference, if value is a null
 /// reference and conversionType is not a value type.</returns>
 /// <remarks>
 /// This method exists as a workaround to System.Convert.ChangeType(Object, Type) which does not handle
 /// nullables as of version 2.0 (2.0.50727.42) of the .NET Framework. The idea is that this method will
 /// be deleted once Convert.ChangeType is updated in a future version of the .NET Framework to handle
 /// nullable types, so we want this to behave as closely to Convert.ChangeType as possible.
 /// This method was written by Peter Johnson at:
 /// http://aspalliance.com/author.aspx?uId=1026.
 /// </remarks>
 public static object ChangeType( object value, Type conversionType )
 {
  // Note: This if block was taken from Convert.ChangeType as is, and is needed here since we're
  // checking properties on conversionType below.
  if( conversionType == null ) {
   throw new ArgumentNullException( "conversionType" );
  } // end if

  // If it's not a nullable type, just pass through the parameters to Convert.ChangeType

  if( conversionType.IsGenericType &&
    conversionType.GetGenericTypeDefinition().Equals( typeof( Nullable<> ) ) ) {
   // It's a nullable type, so instead of calling Convert.ChangeType directly which would throw a
   // InvalidCastException (per http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx),
   // determine what the underlying type is
   // If it's null, it won't convert to the underlying type, but that's fine since nulls don't really
   // have a type--so just return null
   // Note: We only do this check if we're converting to a nullable type, since doing it outside
   // would diverge from Convert.ChangeType's behavior, which throws an InvalidCastException if
   // value is null and conversionType is a value type.
   if( value == null ) {
    return null;
   } // end if

   // It's a nullable type, and not null, so that means it can be converted to its underlying type,
   // so overwrite the passed-in conversion type with this underlying type
   NullableConverter nullableConverter = new NullableConverter( conversionType );
   conversionType = nullableConverter.UnderlyingType;
  } // end if

  // Now that we've guaranteed conversionType is something Convert.ChangeType can handle (i.e. not a
  // nullable type), pass the call on to Convert.ChangeType
  return Convert.ChangeType( value, conversionType );
 }

[/code]

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | Server-Side
Posted by Denny on Wednesday, February 06, 2008 2:20 PM
Permalink | Comments (2) | Post RSSRSS comment feed

.NET Framework Source Released

Back in the saddle!! Scott Guthrie has just let us know that the source code for the .NET Framework libraries, mentioned below, are available for browsing and debugging!

The libraries include:

  • .NET Base Class Libraries (including System, System.CodeDom, System.Collections, System.ComponentModel, System.Diagnostics, System.Drawing, System.Globalization, System.IO, System.Net, System.Reflection, System.Runtime, System.Security, System.Text, System.Threading, etc).
  • ASP.NET (System.Web, System.Web.Extensions)
  • Windows Forms (System.Windows.Forms)
  • Windows Presentation Foundation (System.Windows)
  • ADO.NET and XML (System.Data and System.Xml)

Instructions on installing the libraries for Visual Studio 2008 are located here: Shawn Burke's blog post. Read Scott Gu's post if you want to get the low-down.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by Denny on Wednesday, January 16, 2008 6:36 PM
Permalink | Comments (0) | Post RSSRSS comment feed

LINQ and Enumerable.Cast

I've been using LINQ lately and I've been having a lot of fun with it. It makes working with collections so much better! Many thanks to "Pro LINQ by Joseph C. Rattz" (Amazon) - a great book to get you started on LINQ.

So I ran into a bit of a snafu yesterday and thought I would share some cool LINQ methods.

I was working on a Windows App and using a DataGridView to keep track of some information. I wanted to quickly search through the rows and determine if a rows "filename" column was already in the list. Naturally I wanted to "LINQafy" everything to get it done in one line of code. I quickly ran into the issue that DataGridView.Rows is a DataGridViewRowCollection so I couldn't use IQueryable<DataGridViewRow> because "Source is not IEnumerable<>"

So after a short time playing with DataGridView.Rows.AsQueryable() and also getting nowhere I noticed the Cast extension method. From there it was pretty easy to come up with a solution by reading the method signature:

[code:c#]
DataGridViewRow dgvrow = grid.Rows.Cast<DataGridViewRow>().Where(r => r.Cells["filename"].Value.ToString() == filename).SingleOrDefault();
[/code]

Now I have a reference to the DataGridViewRow (or null if it doesn't exist). It's very useful that using the Cast method will create an IEnumerable<T> so that you can easily do all your LINQ queries.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:
Categories: ASP.NET | Server-Side
Posted by Denny on Monday, January 14, 2008 9:39 AM
Permalink | Comments (0) | Post RSSRSS comment feed

ScreenCast: MVC, jQuery and REST

So I recently picked up a copy of Camtasia Studio (www.techsmith.com) and wanted to give it a shot by creating my first screen cast.

This screen cast is going to show you how to create an MVC application that uses jQuery (http://www.jquery.com/) to do some AJAX calls against a REST url. You should be familiar with jQuery and the MVC framework but I tried to keep it as simple as possible. The screen cast runs for about 25 minutes - Click the image below to start watching.

Comments, questions and suggestions are welcome...

You can download the sample project here: MVCjQueryREST.zip (41.41 kb)

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 4.8 by 6 people

  • Currently 4.833333/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,
Posted by Denny on Sunday, December 16, 2007 8:41 PM
Permalink | Comments (9) | Post RSSRSS comment feed

Extending SubSonic ActiveRecord

I was looking to refactor my User Management class to use SubSonic to do all the DAL processing and I decided to take advantage of SubSonic's Partial Classes to extend Extend!upon my "Account" ActiveRecord and merge my User Management class into the partial class. Note: I'm not referring to the AccountCollection object.

To be completely honest I'm not sure if this is the best way to handle this type of thing but thought it would be a fun exercise if nothing else.

SO let me share with you the code. Some of you may look at it and laugh, some may think it's really cool. Either way I'm throwing this out there so that whatever I learn as a result will help me (and hopefully you).

First lets take a look at the Account Partial Class that SubSonic generates:

[code:c#]
[Serializable]
public partial class Account : ActiveRecord<Account>
{
 ...
}
[/code]

Now there's nothing really important here other than the fact that it's a "Partial Class." So moving on let's see how we extend the class with one of our very own methods: LoginUser().

First we'll look at the code:

[code:c#]
namespace DAL {
public partial class Account
{
 public void LoginUser()
 {
  this.LastLogin = DateTime.Now;
  this.LoginHash = new Guid().ToString(); 

  HttpCookie c = new HttpCookie( "LoginCookie" );
  c.Expires = DateTime.Now.AddDays( 5.0f );
  c.Values.Add( "lastlogin", this.LastLogin );
  c.Values.Add( "loginhash", this.LoginHash ); 

  this.Save( "app-ext-user" );
  HttpContext.Current.Response.Cookies.Add( c );
 }
}
}
[/code]

Now what's really important is how our class is defined. Notice that our class is also a "Partial Class" and it has the same class name as the SubSonic generated class. It's also important to note that our class is defined within the same namespace as the SubSonic generated code - leaving out the namespace will not give you access to the Account constructors. Note: My previous code was inheriting from DAL.Account which was not necessary as pointed out by Kevin in the Comments section.

Within our class definition we have created the LoginUser method. This is the method we're creating to extend the Account class - in other words the method did not exist in the original SubSonic generated Account class.

Within the LoginUser method we use "this" to access the object's properties. "this" is pretty cool because it refers to the currently instantiated Account object (including our newly added method). However you should note that using "this" is not required... you can access the properties, methods, etc... simply by their name. (Kevin - Comments)

So we set a few properties: LastLogin and LoginHash, create a cookie, then we use the Save method to save our changes and also add our newly created login cookie to the Cookies collection.

We've now extended the original SubSonic ActiveRecord class with our LoginUser() method. Give it a shot:

[code:c#]
Account a = new Account(acctid);
if( a.IsLoaded ) a.LoginUser();
[/code]

This is a great way to extend a single SubSonic ActiveRecord with well defined functionality.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 4.0 by 2 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,
Categories: ASP.NET | Server-Side
Posted by Denny on Monday, October 29, 2007 3:15 PM
Permalink | Comments (4) | Post RSSRSS comment feed

SubSonic QueryCommand Object

The QueryCommand object in SubSonic makes writing SQL Commands a whole lot easier and less time consuming. When would you use it? Well sometimes the Query object can't perform complex queries, especially ones involving JOINS. So the QueryCommand is an excellent object to use when you need to run a complex query. Below is an example:

[code:c#]
// The SQL (notice I am using parameters: @projectid)
string cmd1 = "SELECT ListName FROM tList a INNER JOIN tMain b ON b.tId = a.tId WHERE a.tId = @projectid";

// The QueryCommand object...
// SubSonic knows which connection to use based on the provider name “Master” which is defined in Web.Config
// Or leave it blank if you have a default provider selected (also defined in Web.Config)
QueryCommand q = new QueryCommand( cmd1, "Master" );

// Set the parameter(s)
q.AddParameter( "projectid", intProjectId, DbType.Int32, ParameterDirection.Input );

// Execute the command
string strValue = Convert.ToString( DataService.ExecuteScalar( q ) );

// You use the DataService object to execute your QueryCommand object.
// There are several methods you can use with the DataService object including:
//
// DataService.ExecuteQuery(...);
// DataService.ExecuteTransaction(...);
// DataService.GetDataSet(...);
// DataService.GetReader(...);
[/code]

So in 4 lines of code (subtracting comments and breaks) you can run a custom SQL command. Thanks SubSonic!

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 3.5 by 2 people

  • Currently 3.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | Server-Side
Posted by Denny on Thursday, October 04, 2007 11:43 AM
Permalink | Comments (1) | Post RSSRSS comment feed