Archive

Author Archive

Stack Reflections

February 5, 2007 Leave a comment

If you haven’t noticed by my choice of presentation topics, I’m a big fan of Reflection. I like the flexibility and scalability it allows me to build into my applications. There are also some neat little tricks you can use with it, in conjunction with the stack trace, to better track your errors and debugging statements.

First of all, how would you like to be able to write a trace statement that shows your methods called without having to remember to code the method names? This can be accomplished by “walking the stack trace” during a method call and using the reflected method information from the stack to determine what method called your function. It works something like this:

I’m going to write a method called TraceMethodStart with no parameters. This method will load up the stack trace, walk the stack frame back one level, and then write out to Trace the method name and module name of the method that called the TraceMethodStart function.

public void TraceMethodStart()
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
string sMethod = “Unknown method”;
string sClass = “Unknown type”;

//make sure I have frames
if (currentStack.FrameCount > 0)
{
//get the method of the frame one up from me

System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
sMethod = oBase.Name;
sClass = oBase.DeclaringType.ToString();
}

if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write(“Starting: ” + sClass + ” ” + sMethod);

}

Now in my GetRob() function I do this:

namespace Sltc
{
public class Rob
{
public void GetRob()
{
TraceMethodStart();
}
}
}

And a “Starting: Sltc.Rob GetRob” will appear in our trace statements.

Now that’s useful. But it would be even more useful if we knew what was being passed to the function for parameters. Using the params keyword we can extend this function to accept a variable list of arguments so that we can call it from anywhere in our code and get passed any number of arguments. This will allow us to include the variables the function was given when it was called.

public void TraceMethodStart(params object[] oParms)
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
string sMethod = “Unknown method”;
string sClass = “Unknown type”;

//make sure I have frames
if (currentStack.FrameCount > 0)
{
//get the method of the frame one up from me

System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
sMethod = oBase.Name;
sClass = oBase.DeclaringType.ToString();
}

if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write(“Starting: ” + sClass + ” ” + sMethod);

foreach(object obj in oParms)
{
if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write(“Parm: ” + oParm.ToString());
}
}

Now if you are in a method like so, you can do this:

function MyMethod(string s, int i)
{
TraceMethodStart(s, i);
}

Another handy thing you can do with this is to grab the cause for exceptions. A lot of times the stack trace is huge and it’s difficult to track down or even remember to write code to track where your exceptions are occuring. However, if you were to create your own exception, you could use a similar code sequence to grab the cause of the trouble:

public class SLTCException : System.Exception
{

private string _sClass = “Unknown”;
private string _sMethod = “Unknown”;

public SLTCException() : base()
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
if (currentStack.FrameCount > 0)
{
System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
_sMethod = oBase.Name;
_sClass = oBase.DeclaringType.ToString();
}
}
}

Happy stacking!

Rob

Categories: C# Code

Rock n Roll Code Camp Presentations

February 2, 2007 Leave a comment

Hey all,

I spoke at the Rock n Roll Code Camp (http://www.socalcodecamp.com) this past weekend and it went very well. I’m considering giving the same talk / pair of talks in San Diego later this year, or I might come up with a new couple of talks, not sure yet. Always tough when the big hitters take the most common topics. Maybe I’ll flesh out the Generics talk I gave to the User Group a few months ago so that it’s a full hour and give that if no one else pipes in on it!

Anyway, here are links to the ppt and code for the two talks I gave:

Packaging in .NET 3.0: http://www.sanluistech.com/samples/packaging1.zip
Reflection in .NET: http://www.sanluistech.com/samples/reflectiondemo.zip

Have at them, and send me any questions you might have…

Rob

Categories: Code Camp

Querying Profile Values from default Profile Provider

January 31, 2007 Leave a comment

Hey all,

As most of you know if you’ve been involved with the new Membership features of .NET 2.0, there’s a handy way to store user specific settings called the Profile.   This allows you to specify in your config files certain attributes you wish to store on a per user basis.   At compile time, the .NET compiler will adjust its native profile object to account for the profile properties you configure so that you can access them directly with code.

Let’s assume that you are going to store First Name and Last Name on the user profile.  Your configuration would look like this:

<system.web>
  <profile>
    <properties>
    <add name=”FirstName” type=”System.String”/>
    <add name=”LastName” type=”System.String”/>
  </properties>
</system.web>

Once that was done, you could reference those properties directly off of your code:

protected void Page_Load(object sender, EventArgs e)

      Profile.FirstName = ‘John’; 
      Profile.LastName = ‘Smith’;
}

However, there’s a small problem with doing this, and it’s in how the values are stored in the data store that you are using for your Membership and Profile providers.   The names and values of the profile properties are stored in a formatted string format like so:

 The propertynames field:

FirstName:S:0:4:LastName:S:4:5

The propertyvalues field:

JohnSmith

In essence, the propertynames field contains the field name, the datatype, the index, and the length of each field as it exists in the propertyvalues field.

This makes it very difficult to pull data out with simple Sql.

There are several alternatives, including using a SqlTableProvider (found at http://www.asp.net/sandbox/samp_profiles.aspx?tabindex=0&tabid=1), and those are useful if you are looking to do a full blown search mechanism.  But what if you don’t want to replace your entire provider model and do a conversion, and only want to see what data you have?

One thing you can do is construct a user-defined Sql function to parse the propertynames field, and then use that parsing to do an appropriate substring on the propertyvalues field.  Here’s an example.

I’m going to build a user-defined function that takes the text I wish to parse, the field name I am looking for, and the indexed value I am after.  In this example, if I pass in an indexed value of ‘2’ I will get the datatype, ‘3’ will return me the start position, and ‘4’ will get the field length.

CREATE FUNCTION [dbo].[GetProfileParameters](@text varchar(8000), @searchKey varchar(8000), @returnIndex int)
RETURNS varchar(8000)
AS
BEGIN

declare @keyfound bit

set @keyfound = 0

DECLARE @pos smallint,
@index smallint,
@i smallint,
@j smallint,
@s varchar(8000)

SET @pos = 1
set @index = 1

WHILE @pos <= LEN(@text)

BEGIN

       SET @i = CHARINDEX(‘ ‘, @text, @pos)
       SET @j = CHARINDEX(‘:’, @text, @pos)

       IF @i > 0 OR @j > 0
       BEGIN
                   IF @i = 0 OR (@j > 0 AND @j < @i)
                   SET @i = @j

                             IF @i > @pos
                             BEGIN
                                          — @i now holds the earliest delimiter in the string
                                          SET @s = SUBSTRING(@text, @pos, @i – @pos)

                                          if (@s = @searchKey)
                                          begin
                                                –found the key
                                                set @keyfound = 1
                                          end

                                          if (@keyfound = 1 and @index = @returnIndex)
                                          begin
                                                    RETURN @s
                                          end

                                set @index = @index + 1
                                if (@index > 4)
                                         set @index = 1
                     END

                               SET @pos = @i + 1
                               WHILE @pos < LEN(@text) AND SUBSTRING(@text, @pos, 1) IN (‘ ‘, ‘:’)
                               SET @pos = @pos + 1
                   END
          ELSE
                   BEGIN

                              if (@s = @searchKey)
                              begin
                                        –found the key
                                        set @keyfound = 1
                              end

                              if (@keyfound = 1 and @index = @returnIndex)
                              begin
                                        RETURN @s
                              end

                              set @index = @index + 1
                              if (@index > 4)
                                        set @index = 1

                              SET @pos = LEN(@text) + 1
                 END
          END
    RETURN ”
end

Now that we have that, we can get the start index and length of the field we want and get it out of the table by using a substring:

 

select substring(propertyvaluesstring, convert(int, dbo.getprofileparameters(propertynames, ‘FirstName’, 3)) + 1, convert(int, dbo.getprofileparameters(propertynames, ‘FirstName’, 4))) as FieldValue from aspnet_Profile

That will give us all of the first names in the user profiles by doing an appropriate substring on the propertyvalues field, using the data provided in the propertynames field.

Happy querying!

 

Rob

Categories: SQL