CSLA Validation AmbiguousMatchException#

Ran into this error today:

failed in property IsDeleted ---> System.Reflection.AmbiguousMatchException: Ambiguous match found. at System.RuntimeType.GetPropertyImpl

I knew that we happened to have a property on our class called IsDeleted that shadowed a property in the CSLA base class, but I didn't think it should be running into this problem.

After tracking down some reference info here http://msdn.microsoft.com/en-us/library/zy0d4103.aspx I found otu that the issue isn't that we are shadowing, it's that we are shadowing while at the same time changing the type. 

The documentation seems to indicate that both situations should fail, but in my tests, the only time I got the exception was when my shadowing property had a different type.  In this case, we were using a Nullable(of boolean) while the CSLA element was just a plain old Boolean.

I guess we are going to rename our property to make things easy on ourselves, but seeing as how this is codegenerated, it's a little more of a pain than you might think.  But, oh well.

Here is some code that produces the error.  If you change the 2nd property type to a string it works ok.

imports Microsoft.VisualBasic
imports System
Imports System.Collections.Generic

public module MyModule
    sub Main
        dim target as new baseclass
        
        dim p as system.Reflection.PropertyInfo  = target.GetType().GetProperty("Prop") 
        
        wl( p.GetValue(target, nothing))

        
        RL()
    end sub

    #region "Helper methods"

    sub WL(text as object)
        Console.WriteLine(text)
    end sub

    sub WL(text as object, paramarray args as object())
        Console.WriteLine(text.ToString(), args)
    end sub
        
    sub RL()
        Console.ReadLine()
    end sub
    
    sub Break() 
        System.Diagnostics.Debugger.Break()
    end sub

    #end region

end module

public class BaseBaseClass
    public readonly property Prop as string
    get
    return "BaseBaseClass"
    end get
    end property
end class

public class BaseClass 
inherits BaseBaseClass

    public readonly property Prop as integer
    get
    return 123
    end get
    end property

end class
Categories: Programming | .Net | .Net Framework
Monday, March 01, 2010 4:02:49 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Using Asyncronous Tasks In ASP.NET#

ASP.NET has a limited number of threads that it uses to service incoming requests.  Thes threads from the its thread pool, and when its collection of threads are busy, requests have to queue up waiting for an open thread.

But, what happens when you have threads that are blocking waiting for another process to complete?  This could we a database call, or a webservice call, or an IO operation etc.

Well, what happens is that the thread, while doing no real work, is unavailable to service requests.

So, if your database is crunching on some long queries, other simple web requests may be sitting in the queue unable to be handled, even though the webserver CPU is idle.

One solution to this is to use Async pages/methods in ASP.NET 2 or greater.

Async operations allow the thread to be returned back to the thread pool instead of blocking, while some process is executed.

 

There is more than 1 way to do async operations like this from asp.net pages. 

One is to use RegisterAsyncTask and the other to user AddOnPreRenderCompleteAsync as well as declare the page as Async="true".

I won't go into all the details, but AddOnPreRenderCompleteAsync is probably simpler, but you can't define a timeout, you can't call it multiple times in parallel, and in the EndAsyncOperation event handler you can't access things like the httpcontext object.

Here are 2 examples of pages that are asynchronously serving up a PDF document (which is itself served from a page DownloadPDF.aspx, which has a 5 second thread sleep in it to simulate the processing of the report on another server.

Using AddOnPreRenderCompleteAsync:

Imports System.Net
Imports System.IO

Partial Class AsyncServer
    Inherits System.Web.UI.Page

    Dim _request As WebRequest

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        AddOnPreRenderCompleteAsync(New BeginEventHandler(AddressOf BeginAsyncOperation), _
                                    New EndEventHandler(AddressOf EndAsyncOperation))
    End Sub

    Function BeginAsyncOperation(ByVal sender As Object, ByVal e As EventArgs, ByVal cb As AsyncCallback, ByVal state As Object) As IAsyncResult
        _request = WebRequest.Create(HttpContext.Current.Request.Url.Scheme & _
                                     "://" & HttpContext.Current.Request.Url.Authority & _
                                     Page.ResolveUrl("DownloadPDF.aspx"))
        Return _request.BeginGetResponse(cb, state)
    End Function

    Sub EndAsyncOperation(ByVal ar As IAsyncResult)
        Dim reportResponse As WebResponse = _request.EndGetResponse(ar)
        Dim reader As New BinaryReader(reportResponse.GetResponseStream())

        Dim buffer(reportResponse.ContentLength) As Byte
        buffer = reader.ReadBytes(buffer.Length)
        
        Response.Clear()
        Response.ClearHeaders()
        Response.ClearContent()
        Response.ContentType = "Application/pdf"
        Response.BinaryWrite(buffer)
    End Sub

End Class

 

But I prefer to use RegisterAsyncTask.  Now, keep in mind that many operations will already support async versions (webrequests, webservice calls, databases calls, file IO etc), but if there isn't already built in support for an async call, you can make your own method work in this framework with an async delegate.  Check out the commented code below for how you could do this, but because webrequests already support making the call in an asynchronous fashion, I don't need to.

Imports System.Net
Imports System.IO

Partial Class RegisterAsyncTaskServer
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Page.AsyncTimeout = New System.TimeSpan(0, 0, 8)
        Dim task As New PageAsyncTask(New BeginEventHandler(AddressOf BeginGetAsyncData), _
                                      New EndEventHandler(AddressOf EndGetAsyncData), _
                                      New EndEventHandler(AddressOf TimeoutGetAsyncData), "task1", True)

        RegisterAsyncTask(task)
    End Sub

    '*************** This is one way to do this if not using an async download method by creating an async delegate
    'Dim taskDelegate As AsyncTaskDelegate
    '' Create delegate.
    'Delegate Sub AsyncTaskDelegate()
    'Private Function BeginGetAsyncData(ByVal src As Object, ByVal args As EventArgs, ByVal cb As AsyncCallback, ByVal state As Object) As IAsyncResult
    '    Dim extraData As New Object
    '    taskDelegate = New AsyncTaskDelegate(AddressOf DownloadReport)
    '    Dim result As IAsyncResult = taskDelegate.BeginInvoke(cb, extraData)
    '    Return result
    'End Function
    'Private Sub DownloadReport()
    'End Sub

    Private reportRequest As WebRequest

    Private Function BeginGetAsyncData(ByVal src As Object, ByVal args As EventArgs, ByVal cb As AsyncCallback, ByVal state As Object) As IAsyncResult
        reportRequest = WebRequest.Create(HttpContext.Current.Request.Url.Scheme & "://" & _
                                          HttpContext.Current.Request.Url.Authority & _
                                          Page.ResolveUrl("DownloadPDF.aspx"))
        Return reportRequest.BeginGetResponse(cb, state)
    End Function


    Private Sub TimeoutGetAsyncData(ByVal ar As IAsyncResult)
        Response.Write("TIMEOUT")
    End Sub

    Private Sub EndGetAsyncData(ByVal ar As IAsyncResult)
        Dim reportResponse As WebResponse = reportRequest.EndGetResponse(ar)
        Dim reader As New BinaryReader(reportResponse.GetResponseStream())

        Dim buffer(reportResponse.ContentLength - 1) As Byte
        buffer = reader.ReadBytes(buffer.Length)

        Response.Clear()
        Response.ClearHeaders()
        Response.ClearContent()
        Response.ContentType = "Application/pdf"
        Response.BinaryWrite(buffer)
        Response.Flush()
    End Sub

End Class

Nice!

Categories: Programming | .Net | .Net Framework | ASP.Net
Friday, March 13, 2009 10:46:43 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Extending Microsoft Data Access Blocks (early version)#

Microsoft has released several versions of their Data Access Blocks, but they started mixing all their blocks together at some point, so if you wanted to use the DAB, you had to also use the Configuration blocks, and you had to use the Encryption blocks, and those needed the logging blocks etc.

So in many of my projects I have kept with one of the earlier versions.

But, there was a problem.  Basically in order to pass parameters, the easiest way to do it was in an ordinal position way, such as:

Public Shared Sub Whatever(SomeParamsHere)
    Dim storedParams() As SqlParameter
    storedParams = SqlHelperParameterCache.GetSpParameterSet(ConnectionString, "Whatever")

    storedParams(0).Value = 1
    storedParams(1).Value = 2
    storedParams(2).Value = 3
    storedParams(3).Value = "abc"

   SqlHelper.ExecuteNonQuery(ConnectionString, _
        CommandType.StoredProcedure, _
        "ItProjectInfo_General_Update", _
        storedParams)

End Sub

Obviously, this code is hard to read because we don't know which parameters are getting which values w/o opening up the stored procedure and looking ourselves.

So I wrote some extra code to allow of working with SqlParameters in the form of Dictionary(Of String, SqlParameter).  Calling the same function would look like this:

Public Shared Sub Whatever(ByVal SomeParamsHere)
    Dim storedParams() As New Dictionary(Of String, SqlParameter)
    storedParams = SqlHelperParameterCache.GetSpParameterCollection(ConnectionString, "Whatever")

    storedParams.Item("@id").Value = 1
    storedParams.Item("@num").Value = 2
    storedParams.Item("@cat").Value = 3
    storedParams.Item("@name").Value = "abc"

    SqlHelper.ExecuteNonQuery(ConnectionString, _
         CommandType.StoredProcedure, _
         "ItProjectInfo_General_Update", _
         storedParams)

End Sub

This works for output parameters as well.

In order to make this work you need to edit the SqlHelper.vb code.

Inside the SqlHelperParameterCache class you need to add:

Public Overloads Shared Function GetSpParameterCollection(ByVal connectionString As String, ByVal spName As String) As System.Collections.Generic.Dictionary(Of String, SqlParameter)
    Dim parameters() As SqlParameter = GetSpParameterSet(connectionString, spName, False)
    Dim paramsCol As System.Collections.Generic.Dictionary(Of String, SqlParameter)
    paramsCol = SqlHelper.ParamArrayToDict(parameters)
    Return paramsCol
End Function

And inside SqlHelper class you need to add the following methods:

#Region " Dictionary Support Helpers "
Friend Shared Function ParamArrayToDict(ByVal params() As SqlParameter) As Dictionary(Of String, SqlParameter)
    Dim dict As New System.Collections.Generic.Dictionary(Of String, SqlParameter)(StringComparer.CurrentCultureIgnoreCase)
    For i As Integer = 0 To params.Length - 1
        dict.Add(params(i).ParameterName, params(i))
    Next
    Return dict
End Function

Friend Shared Function ParamDictToArray(ByVal dict As Dictionary(Of String, SqlParameter)) As SqlParameter()
    Dim params(dict.Count - 1) As SqlParameter
    Dim i As Integer
    For Each p As SqlParameter In dict.Values
        params(i) = p
        i += 1
    Next
    Return params
End Function
#End Region

Public Overloads Shared Function ExecuteDataset(ByVal connectionString As String, _
                                           ByVal commandType As CommandType, _
                                           ByVal commandText As String, _
                                           ByVal commandParameters As Dictionary(Of String, SqlParameter)) As DataSet ' Execute Dataset with generic dictionary support

    Dim parametersArray() As SqlParameter
    parametersArray = ParamDictToArray(commandParameters)
    Return ExecuteDataset(connectionString, commandType, commandText, parametersArray)
End Function


Public Overloads Shared Function ExecuteNonQuery(ByVal connectionString As String, _
                                              ByVal commandType As CommandType, _
                                              ByVal commandText As String, _
                                              ByVal commandParameters As Dictionary(Of String, SqlParameter)) As Integer
    Dim parametersArray() As SqlParameter
    parametersArray = ParamDictToArray(commandParameters)
    Return ExecuteNonQuery(connectionString, commandType, commandText, parametersArray)
End Function  ' ExecuteNonQuery with generic dictionary support


Public Overloads Shared Function ExecuteScalar(ByVal connectionString As String, _
                                              ByVal commandType As CommandType, _
                                              ByVal commandText As String, _
                                              ByVal commandParameters As Dictionary(Of String, SqlParameter)) As Object

    Dim parametersArray() As SqlParameter
    parametersArray = ParamDictToArray(commandParameters)
    Return ExecuteScalar(connectionString, commandType, commandText, parametersArray)

End Function ' ExecuteScalar with generic dictionary support

 

 

Categories: Programming | .Net | .Net Framework
Thursday, December 04, 2008 1:36:06 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Webservices: The request failed with HTTP status 400: Bad Request#

We have a webservice that is called from an application under heavy use.

From time to time we are getting errors coming back from the webservice:

The request failed with HTTP status 400: Bad Request

The stack trace is not very helpful:

at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)

So basically the webservice is just throwing back a 400 error to the webservice request.

I haven't seen anyone online who has this type of issue.  I have seen several where they ALWAYS get this error, but none where it works most of the time and fails sometimes.

I am considering that it could be something in the network, like a proxy server or AV sniffer, but not sure.

 

Categories: Programming | .Net | .Net Framework | ASP.Net | WebServices
Tuesday, November 18, 2008 5:21:48 PM (Central Standard Time, UTC-06:00) #    Comments [1]  | 

 

Generating Resx Files For Globalization and Localization#

Using resource files (resx files) for globalization is a standard technicque.  ASP.NET allows you to create 1 resx file per page to help you manage your content.

But when it is time to convert those files into the correctly named localized version to send to the translator, you might find yourself doing a lot of copying and renaming.

So I wrote a little script that does this for you:

Imports System.IO
Module Module1

    Sub Main()
        Dim languages() As String = {"es", "pl", "de", "fr"}
        For Each filepath As String In Directory.GetFiles("C:\translationTest")
            If filepath.Contains("x.resx") Then
                For i As Integer = 0 To languages.Length - 1
                    File.Copy(filepath, filepath.Replace(".resx", "." & languages(i) & ".resx"))
                Next
            End If
        Next
    End Sub

End Module

This will generate all the files for you, and then all you need to do is send the off and wait for the translator to do the REAL work :).

Categories: Programming | .Net | .Net Framework | ASP.Net
Tuesday, July 22, 2008 3:13:50 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Where did my columns go?#

I just noticed this while working on a windows forms .net application.

I made some changes to the underlying business objects that I had bound to a datagridview.  Things looked like they should at runtime, but when I opened up the designer, several of my columns were missing!

After some testing around, I realized that any column that was bound to a property on the object, where I had changed the name of the property, was no longer showing.

I figured it would fail the databind or something, but at least let me change the column details to get things working right!

So I added in fake empty property definitions to the business objects and presto: back come the columns.

After that, I was able to update the databinding field and remove my bogus properties.

 

Categories: Programming | .Net | .Net Framework | WinForms
Wednesday, February 13, 2008 6:15:40 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

What could cause this casting error?#

Error:

Unable to cast object of type 'System.Collections.Generic.List`1[EditQuoteController+UnsavedQuoteItemInfo]' to type 'System.Collections.Generic.List`1[EditQuoteController+UnsavedQuoteItemInfo]'.

Yes, you read that right.  Unable to cast object of type X to type X.

I have seen this type of error once before and it was when there were multiple assemblies referencing different version of a common assembly, so even though their names were the same, their versions were different.

But in this instance there is nothing like this that could be having an impact.  All of the classes of consequence are in the same assembly.

Also, I don't get exception very often, only every now and then.

UPDATE:

I think maybe this is happening between builds on my development machine b/c I am storing some data in the session.  So the version in session was from the last build?  Doesn't sound like a great explanation, but it's the best I have at this point.

UPDATE 2:

I am pretty sure that what I wrote in the last update is what is actually happening. 

I used this code:

Try
    list = CType(view.Session.Item(Me.UnsavedKey), List(Of UnsavedQuoteItemInfo))
Catch ex As System.InvalidCastException
    Dim sError As String = "Unable to cast from type " & _
        view.Session.Item(Me.UnsavedKey).GetType.AssemblyQualifiedName & _
        " to type " & GetType(List(Of UnsavedQuoteItemInfo)).AssemblyQualifiedName & _
        ".  The session has been cleared."
    view.Session.Item(Me.UnsavedKey) = Nothing
    Throw New System.ApplicationException(sError)
End Try

Which producted the following 2 types:

System.Collections.Generic.List`1[[EditQuoteController+UnsavedQuoteItemInfo, App_Web_bp-bbqew, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=2.0.0.0, Culture=neutral PublicKeyToken=b77a5c561934e089

System.Collections.Generic.List`1[[EditQuoteController+UnsavedQuoteItemInfo, App_Web_ve7ziow-, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089. 

I am guessing this is a by product of using the web site project, instead of web application project.  There are some other reasons why we wanted to use web site instead of web app on this project, so you don't have to scold me: we made the right choice.

But it seems that every time I make a change to the project, it creates a new dynamically named assembly.  So even though the classes are really the same, they are globally different as far as asp.net is concerned.

 

Categories: Programming | .Net | .Net Framework | ASP.Net
Monday, January 14, 2008 3:14:02 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Using My.Settings on a referenced project#

I recently ran into some seemingly strange behavior as I was testing a couple windows services I had written.

In my case, I had a test harness program that was referencing the service (an exe) but this could also apply to references to dlls if you are using the projects application settings (My.Settings.Whatever in VB.Net).

After figuring it out, it all makes sense.

When you create an application setting by providing a value in the project's "Settings" tab, the value is written out into a special <applicationSettings> block in your config file.

But, in order to make those values accessible via a strongly typed/intellisense method, a class is created to wrap those values.  The class is in the Settings.vb file that is generated when you first add an application setting to your project.

But there is one more interesting thing to note:  If the settings class doesn't find the item it expects in the config file, it will return the last supplied value by default. 

So what this means is that if create an application setting for XYZ for the value "123" and then change the app.config file directly to change the "123" to "abc", then "abc" will be returned when you run the program.  However, if you were to then alter the config file to remove or rename the XYZ item, then your application would return "123" again when it ran.

Also, if you directly modify the config file, and then try to edit the projects applications settings, it will alert you to the fact that some values have changed, and ask if you want to use the updated values from the config file.  If you say yes, it will overwrite the Settings.vb file to use the new values that you had supplied in the config file.

So, I was referencing a project that used these settings, but when I would update the config file, those updated settings were not seen.  All I had to do was go into the project settings tab, allow it to refresh the Settings.vb file, and rebuild the project.

 

Categories: Programming | .Net | .Net Framework | VB.Net
Wednesday, August 22, 2007 8:07:09 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Right aligning text when printing from a .net program#

In a program I am writing, I need to print directly to a couple of label printers.

My God these things are a pain in the ass to work with, but I will leave that rant to another post.

One thing I ran into was how to right align text when using the DrawString method of the System.Drawing.Graphics class off of the PrintPageEventArgs.

The solutions I was coming across seemed about as bad as I was expecting.

They involved measuring the width of the line of string using some System.Drawing.Graphics.MeasureString to figure out the length, and then dynamically position the text to make it appear right aligned.  So what that means is that for short text, X would be greater and for long text X would be less.

Fortunately, I came across the most simple solution:

Dim s As New StringFormat()
s.Alignment = StringAlignment.Far

e.Graphics.DrawString("por que?", New Font("Tahoma", 8), Brushes.Black, 50, 50, s)

Very simple.  But you have to wonder, why did MS pick "Far" as the alignment name instead of "Right", as you would expect.  Maybe "Far" is more of a graphics term for alignment?  Who knows.

 

Categories: Programming | .Net | .Net Framework | WinForms
Monday, August 06, 2007 2:44:24 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

The "Microsoft Crossroads"?#

Sam Gentile thinks that MS is at a crossroads in terms of web development.

He thinks with all the cool, free, cutting edgs stuff out there, like Ruby on Rails, MS may soon lose out on all the "alpha geeks", who move on to newer and better things while MS stays locked in the past.

I'm not ready to crown RoR the winner of anything yet.  True, MS is usually not on the cutting edge, but they usually do a pretty good job adopting good ideas.  There are only a handful of serious RoR sites out there.  If that number grows a ton, then it will mean something. 

Martin Fowler has some similar concerns though, so maybe this will come to fruition.

Categories: Programming | .Net | .Net Framework
Thursday, May 31, 2007 9:15:46 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Software Development and TDD Anti-Patterns#

This is awesome!

Wikipedia has a whole list of programming anti-patterns, and James Carr lists some TDD anti-patterns.

Some of these are pretty funny:

Magic numbers: Including unexplained numbers in algorithms

Superboolean logic: unnecessary comparison or abstraction of boolean arithmetic

Boat anchor: Retaining a part of a system that no longer has any use

Categories: Programming | .Net Framework | Testing
Tuesday, May 29, 2007 11:14:43 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Unit testing data access #

Roy Osherove blogs that he was mistaken when he suggesting using mocks for data access code.  With the improved Rollback attributes that he helped create, along with people like Justin Burtch who created a similar attribute for VSTS, they are now thinking that this is the way to go: rolling back database changes.

Roy is no fan of VSTS testing, finding a few bugs and some questionable design decisions.  Those don't seem like deal breakers for me, but we will see.

Categories: Programming | .Net | .Net Framework | Testing | TFS
Tuesday, May 29, 2007 9:48:11 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

BindingListView#

The BindingList is very nice, but doens't support some things like sort and filter that a lot of people would like to have (see here for a short discussion on BindingList vs Datatable).

This project, in sourceforge, called BindingListView is supposed to allow you to get a sorted or filtered "view" of a bindinglist.

Might be worth checking out.

Categories: Programming | .Net | .Net Framework
Tuesday, May 29, 2007 9:19:00 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Webservices Compression#
Categories: Programming | .Net | .Net Framework | VB.Net | WebServices
Wednesday, May 02, 2007 3:34:54 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

WCF One-Way Calls, Callbacks, And Events#

Here an article I was reading about some of the new (and from the looks of it... very useful) features of WCF.

One-Way calls, callbacks, and events.

Categories: Programming | .Net | .Net Framework
Monday, April 30, 2007 2:03:06 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

ASP.NET Design Patterns#
Categories: Programming | .Net | .Net Framework | ASP.Net
Wednesday, April 11, 2007 10:17:54 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Controlling Programs Remotely#

It looks like from this article that the author is showing how to use remoting to interact with a windows form running on a server.

http://www.codeproject.com/csharp/RemoteWinControls.asp

Pretty interesting.

Categories: Programming | .Net | .Net Framework
Tuesday, April 10, 2007 3:32:23 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

How to get the TOP X rows from a DataTable or DataView#

Here is a function I found that can trim down a datatable/dataview to a limited number of rows.  Basically, it's like doing a "TOP X".

''' <summary>
''' Will return a dataview with only the top "number" of rows.
''' </summary>
''' <param name="myDataView">dataview to "trim"</param>
''' <param name="number">the number of rows to return</param>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetTopDataViewRows(ByVal myDataView As DataView, ByVal number As Integer) As DataView
    Dim tableToClone As DataTable = myDataView.Table.Clone
    Dim i As Integer
    For i = 0 To number - 1
        If i >= myDataView.Count Then Exit For
        tableToClone.ImportRow(myDataView(i).Row)
    Next
    Return New DataView(tableToClone, myDataView.RowFilter, myDataView.Sort, myDataView.RowStateFilter)
End Function

I didn't write this, credit goes to this post.

Categories: .Net | .Net Framework
Friday, February 23, 2007 3:06:17 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Gridview, DateFormatString, and HtmlEncoding#

Here is the original source of this tip.

"for some bizarre reason, you have to set HtmlEncode=false on a bound column in a gridview, to get the DataFormatString to work. "

Categories: Programming | .Net | .Net Framework | ASP.Net
Tuesday, February 20, 2007 11:59:55 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Dealing with WinForms Combobox and name/value items.#

I just read this article on aspalliance.com by Sandeep Archarya.

I think the article had 2 main points.  One was that databinding a combobox is not "bug free" because the act of manually databinding to a combobox causes the SelectedIndexChanged event to fire.  The second point was to show how to create a simple namevalue class to be added to the combobox items collection to get around the "problem" of combobox's taking an object as the item in it's list (as opposed to a name value pair).

I would point out the following:

First, I am not sure that I would call the SelectedIndexChanged event firing a bug.  When you manually databind a list, the first item become selected by default, and thus the selectedindex HAS changed, from -1 to 0.

Second, if you consider this a problem you can get around it a couple different ways.

1) Don't use manual databinding.

In the designer, select a datasource or create a new one.  I created a simple employee object and created an object datasource for this employee.  This creates a EmployeeBindingSource object that I bind my employee list to.  Using this method, I didn't experience the SelectedIndexChanged event firing on the databind.

Private list As New System.Collections.Generic.List(Of employee)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    '*** create some fake employee objects
   For i As Integer = 70 To 80
      list.Add(New employee(i, Chr(i)))
   Next

    '*** this will populate our control (Combobox1)
   Me.EmployeeBindingSource.DataSource = list

End Sub

2) You can use manual databinding, and manually detach and attach the event handler for this event.

Private list As New System.Collections.Generic.List(Of employee)

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
    '*** create some fake employee objects
   For i As Integer = 70 To 80
      list.Add(New employee(i, Chr(i)))
   Next

    '*** remove the handler
    RemoveHandler ComboBox1.SelectedIndexChanged, AddressOf ComboBox1_SelectedIndexChanged
    '*** databind
    Me.ComboBox1.ValueMember = "id"
    Me.ComboBox1.DisplayMember = "name"
    Me.ComboBox1.DataSource = list
    '*** add the handler back
    AddHandler ComboBox1.SelectedIndexChanged, AddressOf ComboBox1_SelectedIndexChanged
End Sub

 

Categories: .Net | .Net Framework | DataBinding | WinForms
Friday, November 10, 2006 4:32:43 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Convert RTF to HTML#

More than once I have looked into a way to convert RTF into HTML.  Mostly because there are RTF textboxes available for winforms, but you might want to save the page as HTML, and not RTF.

This article shows a way to do this that:

http://www.codeproject.com/vb/net/RTFToHTML.asp

Categories: Programming | .Net | .Net Framework
Monday, November 06, 2006 4:33:56 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Make Use Of Culture in SQL Reporting Services Local Reports#

When using SQL Reporting services, you can format things such as dates and currency.

However, depending on the situation you might want to:

  1. Show a report with culture X on a computer running culture Y.
  2. Show a report using the same culture settings as the local computer.

To do (1), all you have to do is set the "Language" parameter of the local report in design time.

To get (2) to work, you need to set the Language parameter of the report as the expression "=User.Language".  This will set the report culture as the culture that the hosting program is running under.

If you have a program that you need to switch between different cultures, you can do so with the following line of code (which changes the culture to "English-Ireland")

System.Threading.Thread.CurrentThread.CurrentCulture = New Globalization.CultureInfo("en-IE", False)

More information can be found at: http://msdn2.microsoft.com/en-us/library/ms156493.aspx

Categories: Programming | .Net | .Net Framework | Reporting
Monday, October 09, 2006 1:43:24 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Performance of Web Services / Remoting / Enterprise Services#

I had previously read and heard in presentations by Rocky Lhotka that performance comparisons between Web Services and Remoting showed that they were basically the same, and that when talking about RPC protocols ES killed them both so badly (order of magnitude) that it wasn't worth fretting over the small diff between WS and remoting.

Rocky kinda explains this position in this post:
http://www.lhotka.net/weblog/RemotingVsWebServicesVsESCOMDCOM.aspx

However, I actually tracked down the white paper on Microsofts website:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwebsrv/html/asmxremotesperf.asp

Much to my suprise the giant performance improvement when using ES was only seen when calling empty functions.  In otherwords, it was basically a test of the transport.  Some "real world" tests showed ES performing faster than most other methods, but sometimes something like Remoting TCP Binary would outperform it as well.

In the tests that actually did something, the performance across the board was usually fairly comperable.  I guess this makes sense.  If you liken the round trip of an RPC call to a person going on a business trip, the speed of the airplane is less important that the time it takes the person to do the job at the end of the trip.  So even if your plane takes 3 hours instead of 2 hours, if your going to be staying for a week then that 1 hour isn't a big deal.

The major conclusion is to not pass datasets.  Datasets are serialized as XML even if you are using the binary serializer.  I have posted some stuff on this topic as well on my blog so you can search for it if you want. 

Categories: Programming | .Net | .Net Framework | Architecture | WebServices
Thursday, September 14, 2006 9:12:30 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Throwing the Right Exception#

Brad Abrams has a good article out there showing a list of all the .net exceptions you can throw from your code.

There are some exceptions that are not shown here, for example ConfigurationException, but this is a good starting point.

From Brad's article:

+--System.Object  

   |

   |

   +--System.Exception  

       |

       |

       +--System.SystemException  

           |

           |

           +--System.ArgumentException  

           |   |

           |   |

           |   +--System.ArgumentNullException  

           |   |

           |   |

           |   +--System.ArgumentOutOfRangeException  

           |   |

           |   |

           |   +--System.DuplicateWaitObjectException  

           |

           |

           +--System.ArithmeticException  

           |   |

           |   |

           |   +--System.DivideByZeroException  

           |   |

           |   |

           |   +--System.OverflowException  

           |   |

           |   |

           |   +--System.NotFiniteNumberException

           |

           |

           +--System.ArrayTypeMismatchException  

           |

           |

           +--System.ExecutionEngineException  

           |

           |

           +--System.FormatException  

           |

           |

           +--System.IndexOutOfRangeException  

           |

           |

           +--System.InvalidCastException  

           |

           |

           +--System.InvalidOperationException  

           |   |

           |   |

           |   +--System.ObjectDisposedException  

           |

           |

           +--System.InvalidProgramException  

           |

           |

           +--System.IO.IOException  

           |   |

           |   |

           |   +--System.IO.DirectoryNotFoundException  

           |   |

           |   |

           |   +--System.IO.EndOfStreamException  

           |   |

           |   |

           |   +--System.IO.FileLoadException  

           |   |

           |   |

           |   +--System.IO.FileNotFoundException  

           |   |

           |   |

           |   +--System.IO.PathTooLongException  

           |

           |

           +--System.NotImplementedException  

           |

           |

           +--System.NotSupportedException  

           |

           |

           +--System.NullReferenceException  

           |

           |

           +--System.OutOfMemoryException  

           |

           |

           +--System.RankException  

           |

           |

           +--System.Security.SecurityException  

           |

           |

           +--System.Security.VerificationException  

           |

           |

           +--System.StackOverflowException  

           |

           |

           +--System.Threading.SynchronizationLockException  

           |

           |

           +--System.Threading.ThreadAbortException  

           |

           |

           +--System.Threading.ThreadStateException  

           |

           |

           +--System.TypeInitializationException  

           |

           |

           +--System.UnauthorizedAccessException 


Jeff Atwood put up another article where he uses a little console app to find all classes named "*Exception". 


Here is his list:


System.AppDomainUnloadedException
System.ApplicationException
System.ArgumentException
System.ArgumentNullException
System.ArgumentOutOfRangeException
System.ArithmeticException
System.ArrayTypeMismatchException
System.BadImageFormatException
System.CannotUnloadAppDomainException
System.ComponentModel.Design.CheckoutException
System.ComponentModel.Design.Serialization.CodeDomSerializerException
System.ComponentModel.InvalidEnumArgumentException
System.ComponentModel.LicenseException
System.ComponentModel.WarningException
System.ComponentModel.Win32Exception
System.Configuration.ConfigurationException
System.ContextMarshalException
System.Data.ConstraintException
System.Data.DataException
System.Data.DBConcurrencyException
System.Data.DeletedRowInaccessibleException
System.Data.DuplicateNameException
System.Data.EvaluateException
System.Data.ExprException
System.Data.InRowChangingEventException
System.Data.InvalidConstraintException
System.Data.InvalidExpressionException
System.Data.MissingPrimaryKeyException
System.Data.NoNullAllowedException
System.Data.Odbc.OdbcException
System.Data.OleDb.OleDbException
System.Data.ReadOnlyException
System.Data.RowNotInTableException
System.Data.SqlClient._ValueException
System.Data.SqlClient.SqlException
System.Data.SqlTypes.SqlNullValueException
System.Data.SqlTypes.SqlTruncateException
System.Data.SqlTypes.SqlTypeException
System.Data.StrongTypingException
System.Data.SyntaxErrorException
System.Data.TypedDataSetGeneratorException
System.Data.VersionNotFoundException
System.DivideByZeroException
System.DllNotFoundException
System.Drawing.Printing.InvalidPrinterException
System.DuplicateWaitObjectException
System.EntryPointNotFoundException
System.Exception
System.ExecutionEngineException
System.FieldAccessException
System.FormatException
System.IndexOutOfRangeException
System.InvalidCastException
System.InvalidOperationException
System.InvalidProgramException
System.IO.DirectoryNotFoundException
System.IO.EndOfStreamException
System.IO.FileLoadException
System.IO.FileNotFoundException
System.IO.InternalBufferOverflowException
System.IO.IOException
System.IO.IsolatedStorage.IsolatedStorageException
System.IO.PathTooLongException
System.Management.ManagementException
System.MemberAccessException
System.Messaging.MessageQueueException
System.MethodAccessException
System.MissingFieldException
System.MissingMemberException
System.MissingMethodException
System.MulticastNotSupportedException
System.Net.CookieException
System.Net.ProtocolViolationException
System.Net.Sockets.SocketException
System.Net.WebException
System.NotFiniteNumberException
System.NotImplementedException
System.NotSupportedException
System.NullReferenceException
System.ObjectDisposedException
System.OutOfMemoryException
System.OverflowException
System.PlatformNotSupportedException
System.RankException
System.Reflection.AmbiguousMatchException
System.Reflection.CustomAttributeFormatException
System.Reflection.InvalidFilterCriteriaException
System.Reflection.ReflectionTypeLoadException
System.Reflection.TargetException
System.Reflection.TargetInvocationException
System.Reflection.TargetParameterCountException
System.Resources.MissingManifestResourceException
System.Runtime.InteropServices.COMException
System.Runtime.InteropServices.ExternalException
System.Runtime.InteropServices.InvalidComObjectException
System.Runtime.InteropServices.InvalidOleVariantTypeException
System.Runtime.InteropServices.MarshalDirectiveException
System.Runtime.InteropServices.SafeArrayRankMismatchException
System.Runtime.InteropServices.SafeArrayTypeMismatchException
System.Runtime.InteropServices.SEHException
System.Runtime.Remoting.MetadataServices.SUDSGeneratorException
System.Runtime.Remoting.MetadataServices.SUDSParserException
System.Runtime.Remoting.RemotingException
System.Runtime.Remoting.RemotingTimeoutException
System.Runtime.Remoting.ServerException
System.Runtime.Serialization.SerializationException
System.Security.Cryptography.CryptographicException
System.Security.Cryptography.CryptographicUnexpectedOperationException
System.Security.Policy.PolicyException
System.Security.SecurityException
System.Security.VerificationException
System.Security.XmlSyntaxException
System.ServiceProcess.TimeoutException
System.StackOverflowException
System.SystemException
System.Threading.SynchronizationLockException
System.Threading.ThreadAbortException
System.Threading.ThreadInterruptedException
System.Threading.ThreadStateException
System.Threading.ThreadStopException
System.TypeInitializationException
System.TypeLoadException
System.TypeUnloadedException
System.UnauthorizedAccessException
System.UriFormatException
System.Web.HttpApplication+CancelModuleException
System.Web.HttpCompileException
System.Web.HttpException
System.Web.HttpParseException
System.Web.HttpRequestValidationException
System.Web.HttpUnhandledException
System.Web.Services.Discovery.InvalidContentTypeException
System.Web.Services.Discovery.InvalidDocumentContentsException
System.Web.Services.Protocols.SoapException
System.Web.Services.Protocols.SoapHeaderException
System.Windows.Forms.AxHost+InvalidActiveXStateException
System.Xml.Schema.XmlSchemaException
System.Xml.XmlException
System.Xml.XPath.XPathException
System.Xml.Xsl.XsltCompileException


The code used to create this list (.net 1.1) is:


Sub Main()
ReflectionSearch(".*exception$")
Console.ReadLine()
End Sub

Sub ReflectionSearch(ByVal strPattern As String)
Dim a As Reflection.Assembly
Dim m As Reflection.Module
Dim t As Type
Dim al As New ArrayList
Dim sl As New SortedList
Dim strAssemblyName As String

For Each strAssemblyName In DefaultAssemblyList()
a = Reflection.Assembly.Load(strAssemblyName)
For Each m In a.GetModules
For Each t In m.GetTypes
al.Add(t)
Dim strFullName As String = t.FullName
If Regex.IsMatch(strFullName, strPattern, RegexOptions.IgnoreCase) Then
sl.Add(strFullName, Nothing)
End If
Next
Next
Next

Dim de As DictionaryEntry
For Each de In sl
Console.WriteLine(de.Key)
Next
Console.WriteLine(sl.Count.ToString & " matches for " & strPattern)
End Sub

Function DefaultAssemblyList() as ArrayList
Dim al As New ArrayList
With al
.Add("mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
.Add("System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
.Add("System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
.Add("System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
.Add("System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
.Add("System.Xml, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
.Add("System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.DirectoryServices, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.Drawing.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.Messaging, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.Runtime.Serialization.Formatters.Soap, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.Security, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.ServiceProcess, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.Web, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.Web.Services, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
.Add("System.Management, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
End With
Return al
End Function

System.Xml.Xsl.XsltException


Categories: Programming | .Net | .Net Framework | Architecture
Thursday, August 10, 2006 11:07:53 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Accessing DLLs stored in the GAC#

You can access the dlls by going to this undocumented folder:

C:\WINDOWS\ASSEMBLY\GAC_MSIL

If you go to C:\WINDOWS\ASSEMBLY\ it will not show you the GAC_MSIL folder, but rather a view of all DLLs that you can't copy.

 

Categories: Programming | .Net | .Net Framework
Wednesday, August 09, 2006 11:35:34 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Expresso Regular Expression Tool#

Expresso is a free tool that you can download and run to aid you in building and testing regular expressions.

It's pretty handy!

Categories: Programming | .Net | .Net Framework | Utilities
Monday, July 31, 2006 10:19:54 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Validating XML document against an XML Schema with VB.Net#

It seems like validating an XML document against a schema would be a pretty simple thing to do in the .Net framework, seeing as how they have such deep support for dealing with XML.

But as of yet, I haven't found a simple way to do it.

Here is the code I have been using to validate XML against an XML Schema.

Imports System.IO
Imports System.Xml
Imports System.Xml.Schema


Private schemaValidation As New ValidationEventHandler(AddressOf ValidationHandler)

Private Function ValidateXml(ByVal xmlFileName As String, ByVal xmlSchemaName As String) As Boolean
Using myFile As New FileStream(xmlFileName, FileMode.Open, FileAccess.Read, FileShare.None)
Dim xDoc As New Xml.XmlDocument()
xDoc.Load(myFile)
xDoc.Schemas.Add(GetSchema(xmlSchemaName))
Try
xDoc.Validate(schemaValidation)
Return True
Catch ex As XmlSchemaValidationException
Console.Write(ex.ToString)
Return False
Catch ex As XmlSchemaException
Console.Write(ex.ToString)
Return False
Catch ex As Exception
Console.Write(ex.ToString)
Return False
End Try
End Using
End Function

Private Function GetSchema(ByVal filePath As String) As XmlSchema
Dim schema As XmlSchema
Using s As New System.IO.FileStream(filePath, FileMode.Open)
Using reader As New StreamReader(s)
schema = XmlSchema.Read(reader, Nothing)
End Using
End Using
Return schema
End Function

Private Sub ValidationHandler(ByVal sender As Object, ByVal e As System.Xml.Schema.ValidationEventArgs)
Throw e.Exception
End Sub
 
Categories: Programming | .Net | .Net Framework | VB.Net | XML
Saturday, July 29, 2006 4:35:25 PM (Central Daylight Time, UTC-05:00) #    Comments [2]  | 

 

XSL Transformations in .NET 2.0#

I found this article that talks about some of the classes used in the .net framework v2.0 when doing XSLT.

http://www.15seconds.com/issue/060608.htm

I am taking a course on XML / XSLT at UofC that I am planning on doing in .Net.  I have written xml schamas xml stylesheets and xml transforms before, but not using .net 2.0, so it should be interesting.

Categories: Programming | .Net | .Net Framework | University of Chicago
Monday, June 26, 2006 1:12:49 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Exceptions in .Net#

I found this snippet on another site, and it looks like it comes from the book I just bought about building frameworks from the guys that worked on the .net framework.

  • DO report execution failures by throwing exceptions.
  • CONSIDER terminating the process by calling System.Environment.FailFast (.NET 2.0) instead of throwing an exception, if your code reaches a situation where you consider it unsafe for further execution.
  • DO NOT use exceptions for the normal flow of control, if possible.
  • CONSIDER the performance implications of throwing exceptions.
  • DO document all exceptions thrown by publicly callable members because of a violation of the member contract and treat them as part of your contract.
  • DO NOT have public members that can either throw or not based on some option such as a bool parameter (.e.g., bool throwOnError)
  • DO NOT have public members that return exceptions as the return value or as an out parameter.
  • CONSIDER using exception builder methods.
  • DO NOT throw exceptions from exception filter blocks
  • AVOID explicitly throwing exceptions from finally blocks.
  • DO throw the most specific (the most derived) exception that makes sense.
  • DO NOT swallow errors by catching nonspecifc exceptions ( e.g., catch (Exception e) { } // swallowed whole!)
  • CONSIDER catching a specific exception when you understand why it was thrown in a given context and you can respond to the failure programmatically.
  • DO Clean up any side effects when throwing an exception. For example, if a Hashtable.Insert method throws an exception, the caller can assume that the specified item was not added to the Hashtable.
  • DO NOT derive all new exceptions directly from the base class SystemException. Inherit from SystemException only when creating new exceptions in System namespaces. Inherit from ApplicationException when creating new exceptions in other namespaces.
  • DO use the predefined exceptions types. Define new exception types only for programmatic scenarios.
  • DO NOT overcatch. Exceptions should often simply be allowed to propagate up the call stack.
  • DO prefer using an empty throw when catching and rethrowing an exception. This is the best way to preserve the exception call stack.
  • AVOID creating custom exception classes when there is already an exception type that's "good enough".
  • DO Design classes so that in the normal course of use an exception will never be thrown.
  • DO NOT return Error Codes!
  • Categories: Programming | .Net | .Net Framework
    Wednesday, June 21, 2006 1:52:51 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    Problems moving from System.Web.Mail to System.Net.Mail#

    I recently went through the painful process of updating all our codebase to remove all warning messages after our "successful" convesion from .net 1.1 to 2.0.

    After I made all the adjustments to remove all warnings, all seemd to be well.  In fact, it was going to well, as this morning I relized that I hadn't seen an exception report come through my email in a week.

    Sure enough, I went into the database where I log everything and found exceptions that were not being emailed to our development team.

    The exceptions that were being thrown when we tried to email were stuff like this:

    Email address problemsError sending Error Report: Message: The specified string is not in the form required for an e-mail address.
    Stack:   at System.Net.Mime.MailBnfHelper.ReadMailAddress(String data, Int32& offset, String& displayName)
       at System.Net.Mime.MailBnfHelper.ReadMailAddress(String data, Int32& offset)
       at System.Net.Mail.MailAddressCollection.ParseValue(String addresses)
       at System.Net.Mail.MailAddressCollection.Add(String addresses)
       at System.Net.Mail.Message..ctor(String from, String to)
       at System.Net.Mail.MailMessage..ctor(String from, String to)
       at System.Net.Mail.MailMessage..ctor(String from, String to, String subject, String body)
       at Walshgroup.Logging.ApplicationAudit.EmailErrorToDevelopmentTeam(String sErrorMessage, Int32 iLoginID) in x.vb:line 586 on machine y

    Subject problemsError sending Error Report: Message: The specified string is not in the form required for a subject.
    Stack:   at System.Net.Mail.Message.set_Subject(String value)
       at System.Net.Mail.MailMessage..ctor(String from, String to, String subject, String body)
       at Walshgroup.Logging.ApplicationAudit.EmailErrorToDevelopmentTeam(String sErrorMessage, Int32 iLoginID) in C:\x.vb:line 586 on machine y

    It turns out that we were doing 2 things that System.Web.Mail seemed to accept, but System.Net.Mail did not.

    Email Address: We were using the MS Outlook way of email concatenation (using a semicolon) to send an email to multiple people (e.g. bill@asdf.com;jack@asdf.com;pete@asdf.com).  Once I changed it to use commas, everything worked, but we still had errors related to the subject line.

    What we were doing for the subject line was simply to take the first 50 characters of the email error message.  In this case, this included some CRLF.  Once those were removed the email sent w/o a problem.

    For more info on these classes check out http://www.systemwebmail.com/ and http://www.systemnetmail.com/.

    Categories: Networking | Email | Programming | .Net | .Net Framework
    Thursday, June 01, 2006 4:33:55 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    Microsoft Releases LINQ CTP#

    Microsoft has released LINQ CTP.

    While it is not expected that this will become fully released until the next version of Visual Studio (2008?) it is not something bad to look at now.

    Categories: Programming | .Net | .Net Framework | Architecture
    Wednesday, May 17, 2006 8:47:12 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    Creating a Sortable BindingList#

    This article from MSDN talks about custom databinding, but specifically it talks about the issues raised when you are trying to databind a custom collection to a datagridview.

    Using a List<T> will work, but when all is said and done you lose some nice features such as sorting.

    Categories: Programming | .Net | .Net Framework | ASP.Net | WinForms
    Wednesday, May 17, 2006 8:43:51 AM (Central Daylight Time, UTC-05:00) #    Comments [1]  | 

     

    Run ASP.NET Web Server From Any Folder#

    Rob McLaws has this cool extension that lets you click on a folder and run a webserver from it.

    The article, with some comments on alternative ways to do it, or ways to improve it can be found here.

    http://weblogs.asp.net/rmclaws/archive/2005/10/25/428422.aspx

    From the page:

    I've been doing some web development work again lately, and I haven't wanted to screw with setting up IIS on my virtual machine. The .NET Framework 2.0 comes with a built-in webserver, based on the old Cassini web server. So I wanted to be able to easily set up any directory to have its contents served up on an as-needed basis. The result is an addition to the Windows Explorer right-click menu, as shown below:

    This is enabled by a simple modification to the registry. You can take the text below and dump it into a file named "WebServer.reg", and then run it, to immediately get the item in the context menu.

    Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\VS2005 WebServer]
    @="ASP.NET 2.0 Web Server Here"

    [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\VS2005 WebServer\command]
    @="C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\Webdev.WebServer.exe /port:8080 /path:\"%1\""

    There are a couple caveats to this tool, however:

    1. The web server does not randomly assign a port number, so it has to be hard-coded into the registry.
    2. The web server does not automatically assign a virtual directory, so it will always be "http://localhost:port"
    3. A command prompt window will be spawned, and cannot be closed without closing the web server process.

    Moving foward, there are a couple of options to fix these issues:

    1. Someone who knows more about variables in the registry can help me fix issues #2 and #3
    2. I can build a wrapper executable that solves all three problems
    3. Microsoft can put in a DCR and fix it before it goes gold in a few days.

    #3 is not likely, so I'd love to hear what you think. Hope this trick is useful.

     

    Categories: .Net | .Net Framework | ASP.Net | Tools
    Tuesday, May 09, 2006 3:55:26 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    applicationSettings, appSettings. app.config, web.config and userSettings#

    I have seen lots of posts from people in the newsgroups trying to figure out what the deal is with the new config options in .net 2.0.

    The main reason people run into problems is due to MS making a number of changes, including changes between the beta and the RC product, resulting in different answers based on how early you encountered the issues.

    You can still do things the way you did with .Net 1.x.

           <appSettings>

                  <add key="MyKeyName" value="somevalue"/>

           </appSettings>

    and then you can access it with:

    Dim myvalue As String = System.Configuration.ConfigurationSettings.AppSettings.Item("ConnectionString")

    However, if you try this, VS.Net will warn you:

    This method is obsolete, it has been replaced by System.Configuration!System.Configuration.ConfigurationManager.AppSettings

    It is important to note that the "!" above indicates that the fully quallified class listed, is located in the System.Configuration assembly, which of course you have to add to your project. 

    So unlike previous versions, you need to manually add a reference to System.Configuration in order to make this new call.

    Now, .net 2.0 and vs.net 2005 have teamed up to offer a new option for storing user settings which may seem more complicated at first if you don't know exactly what you are doing.  In the project properties you can select a "Settings" tab where you are able to modify application settings, which are in turn stored in app.config.  These settings can either be "User" settings, or "Application" settings. 

    Application settings are stored in the app.config (or web.config), and are read-only.  User settings have a default value that is stored in the app.config, but your application can overwrite these default values as needed, and the users settings will be stored in:

    %USERPROFILE%\Local Settings\Application Data\<Company Name>\<appdomainname>_<eid>_<hash>\<verison>\user.config. (non roaming)

    OR:

    %USERPROFILE%\Application Data\<Company Name>\<appdomainname>_<eid>_<hash>\<verison>\user.config (roaming)


    The other nice feature of the 2.0 way of accessing these settings is that the settings are saved as a specific type from a wide collection of available types (String, System.DateTime, System.Drawing.Color, System.Guid, Bool, StringCollection etc) and when you access them from your code they are available in intellisense.

    This may seem like it isn't important, but it means you can't mistype a setting key, or accidently try an invalid cast from one of your settings.  Also, storing a collection was a real pain in 1.x.    Now you can create a collection quickly and it will be added to the user settings like this:

       <setting name="MyCol" serializeAs="Xml">

            <value>

                <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

                    xmlns:xsd="http://www.w3.org/2001/XMLSchema">

                    <string>I am first</string>

                    <string>second</string>

                    <string>me third</string>

                    <string>I am number four</string>

                </ArrayOfString>

            </value>

        </setting>

    Pretty nice!

    To access these properties you have 2 different ways depending on if you are using VB.Net or C#.

    For VB.Net you use the "My" namespace and access it like this:

    Dim mySetting As String = My.Settings.MySetting

    For C# you access these settings through the "Properties" object

           string mySetting = Properties.Settings.Default.MyUserSetting;

    That's it!

    Categories: Programming | .Net | .Net Framework | C# | VB.Net
    Wednesday, April 26, 2006 8:36:40 AM (Central Daylight Time, UTC-05:00) #    Comments [9]  | 

     

    Serialization / Deserialization of Objects With Version Changes#

    CSLA as well as well as the proxy architecture I created for my last project, utilize serialization of objects to be passed across the wire, and deserialized on the other side into the same type of object.

    This is different from passing datasets, which are then read into business objects.  We are actually passing the serialized version of the business object.

    So what happens if you make a change to a business object such as adding a public property.  Will clients who have the old version of the Business Object be forced to upgrade? 

    To see the answers along with some sample code for testing this out click on the link to read the full article.

    So lets say you have a class that exposes 20 properties and 40 methods.  This business object is deployed on hundreds of clients computers.  When they send the BizObject over the wire, it is deserialized back into the exact same object on the server. 

    But now, for whatever reason, you need to add 1 property to this BizObject.  For the current set of clients using this business object, you don't really need to deploy the updated change unless you have to in order to keep it from breaking.

    So do you need to redeploy?  Probably not.

    I serialzied a business object into a base64 encoded string and then added a public property to the object and tried to deserialize it with the "old" serialized string.  The result?  It worked.  The properties that had values when I first serialized it kept their values.  The fact that there were new properties didn't cause a problem.

    How about going the other way: removing a public property that had a value when it was serialized, but doesn't exist with deserialized.  Again, this works. 

    When doesn't it work?  When you are trying to deserialze into a different class, or a different namespace for the same class. 

    So you can't serialize classA and deserialize it into classB, even if both expose the exact same signature.  The same goes for namespaces.  If you serialize classA, and then change it's namespace and try to deserialize it, you will get an exception.

    You can try it out with the following code:

    Imports WindowsApplication1.ASDF


    Public Class Form1

    Private Sub toString_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdToString.Click
    Dim o As New A
    o.A11 = "this is a test"
    o.Asdf1 = "another test"

    Me.TextBox2.Text = EncodeBase64(o.CloneString)
    MsgBox(EncodeBase64(o.CloneString))
    End Sub

    Private Sub fromString_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles fromString.Click
    Dim o As A = A.Hydrate(DecodeBase64(Me.TextBox1.Text))
    MsgBox(o.A11)
    MsgBox(o.Asdf1)
    MsgBox(o.asdfdsa)
    End Sub

    Public Function EncodeBase64(ByVal input As String) As String
    Dim strBytes() As Byte = System.Text.Encoding.UTF8.GetBytes(input)
    Return System.Convert.ToBase64String(strBytes)
    End Function

    Public Function DecodeBase64(ByVal input As String) As String
    Return System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(input))
    End Function

    End Class


    <Serializable()> _
    Public Class Parent

    Public Function CloneString() As String
    Dim bFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
    Dim stream As New System.IO.MemoryStream()
    bFormatter.Serialize(stream, Me)
    stream.Flush()
    stream.Position = 0
    Dim bytes() As Byte = stream.ToArray()

    Return System.Text.Encoding.Default.GetString(bytes)
    End Function

    Public Shared Function StringToStream(ByVal str As String) As System.IO.Stream
    Return New System.IO.MemoryStream(System.Text.Encoding.Default.GetBytes(str))
    End Function

    End Class

    <Serializable()> _
    Public Class A
    Inherits Parent

    Private a1 As String
    Private asdf As String
    Public Property A11() As String
    Get
    Return a1
    End Get
    Set(ByVal value As String)
    a1 = value
    End Set
    End Property

    Public Property Asdf1() As String
    Get
    Return asdf
    End Get
    Set(ByVal value As String)
    asdf = value
    End Set
    End Property
    Public Function asdfdsa() As String
    Return "Asdf"
    End Function
    Public Shared Function Hydrate(ByVal s As String) As A
    Dim bFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
    Dim stream2 As System.IO.MemoryStream = StringToStream(s)
    stream2.Flush()
    stream2.Position = 0
    Dim newClone As A
    newClone = CType(bFormatter.Deserialize(stream2), A)
    Return newClone
    End Function

    End Class


     

    Categories: Programming | .Net | .Net Framework | Architecture
    Sunday, April 23, 2006 7:35:24 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    App.Config functionality for Class Library Assembiles#

    I was just reading this site:

    http://www.bearcanyon.com/dotnet/#AssemblySettings

    I downloaded the sample code (link below).  It is supposed to allow you to have a config file per assembley e.g. MyAssembly.dll.config. 

    I haven't looked at the code, but I guess you would just write something that uses reflection to find the assembly name, and then look for an xml file to read.

    AssemblySettings.zip (10.5 KB)

     

    Categories: Programming | .Net | .Net Framework | Tools
    Thursday, April 20, 2006 2:25:32 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    VB.Net: Passing Reference and Value Objects ByRef and ByVal#

    Here is a little example of how vb.net deals with passing of objects ByRef and ByVal.  The short answer is that when you pass a reference type object (not a value type) byval, the object is copied back when the method if finished.  You never really have handle on the original object, which is evident by the fact that you can't set it = nothing.  However, if you pass ByRef then you can indeed set the object = nothing and it will remain null when you return to the calling function.

    If you try the same thing, except using a value type structure, you will see almost the same behavior, except for the major differenct that if you pass a structure byval and then make a change to it, those changes will not be copied back to the calling function.

    To see an example of this check out the code by clicking on the "More" button to read the full article. 
    Categories: Programming | .Net | .Net Framework | VB.Net
    Saturday, April 15, 2006 1:04:46 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    Databinding in .Net 2.0 (DNR TV)#

    Brian Noyes is the guest on DNR TV to cover databinding in .Net 2.0.

    The video can bee seen here.

    Categories: Code Links | .Net Framework | Web Site Links
    Monday, April 10, 2006 6:26:51 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    Implementing ICloneable While Staying Type Safe#

    I had always had issue with implementing ICloneable in the .Net Framework on my classes.  Implementing ICloneable requires that you return an Object, but a lot of time you don't want to return an Object type, you want to return a strongly typed object of type whatever.

    Well, thanks to a tip I heard on .NetRocks from Rocky Lhotka, I have coded up an example of how you can a) Implement ICloneable, and b) return a strongly typed object from your Clone method.

    Imports System

    Public Class BusinessObject
    Implements ICloneable
    Private Function privateClone() As Object Implements ICloneable.Clone
    Dim MyClone As Object = makeClone()
    Return MyClone
    End Function
    Public Function Clone() As BusinessObject
    Dim MyClone As BusinessObject = makeClone()
    Return MyClone
    End Function
    Private Function makeClone() As BusinessObject
    '*** do the clone here
    End Function End Class

    The trick is to implement ICloneable as a private function.  To be honest I have no idea why this works.  You would think that implementing the Clone method as a private function would mean that you couldn't access it, but as the code I wrote below shows, it does work.

    imports Microsoft.VisualBasic
    imports System
    imports System.Collections

    public module MyModule
        sub Main
    RL()
            dim o as new BusinessObject
            WL("IClone " & o.Clone.IClone)
            WL("StandardClone " & o.Clone.StandardClone)
            dim i as System.ICloneable
            i = ctype(o, System.ICloneable)
            WL("IClone " & ctype(i.Clone,BusinessObject).IClone)
            WL("StandardClone " & ctype(i.Clone,BusinessObject).StandardClone)
            RL()
        end sub

        #region "Helper methods"

        sub WL(text as object)
            Console.WriteLine(text)
        end sub

        sub WL(text as object, paramarray args as object())
            Console.WriteLine(text.ToString(), args)
        end sub
            
        sub RL()
            Console.ReadLine()
        end sub
        
        sub Break()
            System.Diagnostics.Debugger.Break()
        end sub

    #end region

    end module


    public Class BusinessObject
    Implements System.ICloneable
        public IClone as string = ""
        public StandardClone as string = ""

    Private Function privateClone() As Object Implements ICloneable.Clone
    Dim MyClone As Object = makeClone()
            ctype(MyClone,BusinessObject).IClone = "true"
    Return MyClone
    End Function

    Public Function Clone() As BusinessObject
    Dim MyClone As BusinessObject = makeClone()
            MyClone.StandardClone = "true"
    Return MyClone
    End Function

    Private Function makeClone() As BusinessObject
    '*** do the clone here
            return new BusinessObject
    End Function

    End Class

    I will have to get to the bottom of this private thing.  But at least this will work and do you want expect it to.

    Update: I got some answers from a couple people online.
    Alvin Bruney (
    http://msmvps.com/blogs/Alvin/ ) suggested:

    The modify tag, private, does not apply to the compiler. It is capable of
    calling the method. The tag is applicable only to calling code.

    This I knew, but I guess I was wondering why the compiler allows you to do this.  I guess it makes sense that the interface makes that method public, so public it is!   Case closed

    Categories: .Net Framework | VB.Net | C#
    Monday, April 10, 2006 9:10:44 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    Troubleshooting .NET Applications - Knowing Which Tools to Use and When#
    This whitepaper: Troubleshooting .NET Applications - Knowing Which Tools to Use and When talks about different methods for debugging .net applications, and talks about the various tools available to aid in the debugging efforst.
    Categories: .Net Framework | Tools
    Friday, March 24, 2006 7:27:28 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

     

    Best Practices for Problem Resolution and Production Support of .NET Applications#
    This Whitle Paper discusses some of the well defined practices for supporting and scaling .net applications.
    Categories: .Net Framework
    Friday, March 24, 2006 7:26:15 PM (Central Standard Time, UTC-06:00) #    Comments [2]  | 

     

    Strong Names and Security in the .NET Framework#
    This Security Brief at MSDN talks about the practice of strongly naming your .net assemblies.
    Categories: Programming | .Net | .Net Framework | Security
    Wednesday, March 24, 2004 8:23:50 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

     

    Windows Principal and Identity Objects#
    Here is the article... that all.
    Categories: Programming | .Net | .Net Framework | Security | Authentication
    Thursday, March 18, 2004 7:44:21 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

     

    SQL Stress Test and SQL Server .NET CLR#
    Here and here are 2 articles from SQL Junkies.

    The first deals with the .NET CLR and it's role in the upcoming version of SQL Server, called Yukon.

    The second talks about a tool that you can use to run a stress test on a SQL Servers disk setup.
    Categories: Programming | .Net | .Net Framework | Database | T-Sql
    Saturday, February 07, 2004 12:43:26 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

     

    .Net Code Access Security#
    Here is an article that goes into code access security.
    Categories: Programming | .Net | .Net Framework | Security
    Tuesday, December 30, 2003 12:25:43 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

     

    Fundamentals of IDisposable #
    I think VS.NET kinda does a lot of this already by default when you create a new class... maybe not.

    I wrote a macro that enters a bunch of code to do a lot of this, maybe I'll post it up here if I remember.

    Here is a link to the article.
    Categories: Programming | .Net | .Net Framework
    Thursday, September 11, 2003 11:03:28 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    MSIL, CLR, .NET and Obfuscation Options#
    This article does a good job covering the topic of protecting your code. It shows how easliy you can use a decompiler (posted on this site earlier) to view the source code of a .NET exe or dll. It then goes into some details about how you can use different tools for .NET Obfuscation to help make reverse engineering your code a little more difficult (including a string literal encryption option?).
    Categories: Code Links | Programming | .Net | .Net Framework
    Wednesday, August 06, 2003 2:25:37 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    Persisting Objects#
    Here are some articles on persisting objects:
    1
    2
    3
    Categories: Programming | .Net | .Net Framework
    Thursday, July 03, 2003 2:54:18 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    DataBinding Custom Objects in .NET#
    This article talks about how to make your classes so that they can be bound to user controls.
    Categories: Programming | .Net | .Net Framework
    Thursday, July 03, 2003 12:30:42 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    .NET Code Generation From XSLT#
    This article talks about generating .NET code, mainly the strongly typed dataset, from XSLT. I was skimming it because I didn't really need the primer on XSLT, but I never saw where he got his XML file from to transform. I didn't see anything about automating this either... I don't really use the DataSet very much. I use the DataReader and DataTable more. I don't understand why you can drag a table onto a designer to get its schema, but you can't do the same for stored procedures that return data. Oh well.
    Categories: Programming | .Net | .Net Framework | Tools
    Tuesday, June 17, 2003 9:36:39 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

     

    Microsoft Application Blocks for .NET#
    Microsoft Application Blocks for .NET
    Categories: Code Links | Programming | .Net | .Net Framework | Tools
    Monday, June 09, 2003 2:38:35 PM (Central Daylight Time, UTC-05:00) #    Comments [1]  | 

     

    More LDAP DirectoryEntry Issues...#
    I should have known it wasn't over.

    I am still making steady progress, but I am still finding stupid problems along the way.

    Someone told me that they thought my assessment of my security problem was correct, that I need to get the ASP.NET worker thread to have higher access, not the default IIS user account, by using impersonation. I havn't found a way to do impersonation on just 1 page, so I think I will need to move the login page to a different directory and add another .config file.

    Some of the goofy things I am finding are:
    1. When searching the directory for a user object, if you want to later call the .Invoke("SetPassword",agrs[]) then you need to specify the schema as "user" when doing the cnAD.Children.Find("CN=MyUser","user") method.
    2. If you try to invoke the ADSI "SetPassword" and you try to use the same password that the account already has, it will throw an error.
      I'm guessing this is because there is probably something indicating that the user must change the password or something, to get around this, I am first changing the password to a GUID, and then changing it again to what I want it to be.
      Call cnNewUser.Invoke("SetPassword", New Object() {New Guid().ToString()})
      Categories: Programming | .Net | .Net Framework | VB.Net
      Wednesday, May 28, 2003 2:50:06 PM (Central Daylight Time, UTC-05:00) #    Comments [3]  | 

       

      Adding User Through LDAP#
      I have been fighting with this damn thing for a long time now. The internet is covered with articles like this one from CodeProject.com, but no matter what I do, I can't seem to be able to set the password of a user that I create through LDAP. It doesn't really help that almost all the example code is C#, and I am working with VB.NET. The conversion isn't a big deal, but when you don't know what the problem is, I would rather see a VB.NET example somewhere.

      When I try to call the Invoke method, with "SetPassword" and a new password, I always get back "Logon failure: unknown user name or bad password".

      So frustrating....
      Categories: Code Links | Programming | .Net | .Net Framework | VB.Net
      Tuesday, May 27, 2003 2:27:14 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

       

      All content © 2010, Christopher May, Inc
      Open Job Positions
      On this page
      CSLA Validation AmbiguousMatchException
      Using Asyncronous Tasks In ASP.NET
      Extending Microsoft Data Access Blocks (early version)
      Webservices: The request failed with HTTP status 400: Bad Request
      Generating Resx Files For Globalization and Localization
      Where did my columns go?
      What could cause this casting error?
      Using My.Settings on a referenced project
      Right aligning text when printing from a .net program
      The "Microsoft Crossroads"?
      Software Development and TDD Anti-Patterns
      Unit testing data access
      BindingListView
      Webservices Compression
      WCF One-Way Calls, Callbacks, And Events
      ASP.NET Design Patterns
      Controlling Programs Remotely
      How to get the TOP X rows from a DataTable or DataView
      Gridview, DateFormatString, and HtmlEncoding
      Dealing with WinForms Combobox and name/value items.
      Convert RTF to HTML
      Make Use Of Culture in SQL Reporting Services Local Reports
      Performance of Web Services / Remoting / Enterprise Services
      Throwing the Right Exception
      Accessing DLLs stored in the GAC
      Expresso Regular Expression Tool
      Validating XML document against an XML Schema with VB.Net
      XSL Transformations in .NET 2.0
      Exceptions in .Net
      Problems moving from System.Web.Mail to System.Net.Mail
      Microsoft Releases LINQ CTP
      Creating a Sortable BindingList
      Run ASP.NET Web Server From Any Folder
      applicationSettings, appSettings. app.config, web.config and userSettings
      Serialization / Deserialization of Objects With Version Changes
      App.Config functionality for Class Library Assembiles
      VB.Net: Passing Reference and Value Objects ByRef and ByVal
      Databinding in .Net 2.0 (DNR TV)
      Implementing ICloneable While Staying Type Safe
      Troubleshooting .NET Applications - Knowing Which Tools to Use and When
      Best Practices for Problem Resolution and Production Support of .NET Applications
      Strong Names and Security in the .NET Framework
      Windows Principal and Identity Objects
      SQL Stress Test and SQL Server .NET CLR
      .Net Code Access Security
      Fundamentals of IDisposable
      MSIL, CLR, .NET and Obfuscation Options
      Persisting Objects
      DataBinding Custom Objects in .NET
      .NET Code Generation From XSLT
      Microsoft Application Blocks for .NET
      More LDAP DirectoryEntry Issues...
      Adding User Through LDAP
      Google Ads
      This site
      Calendar
      <March 2010>
      SunMonTueWedThuFriSat
      28123456
      78910111213
      14151617181920
      21222324252627
      28293031123
      45678910
      Archives
      Sitemap
      Blogroll OPML
      Disclaimer

      Powered by: newtelligence dasBlog 2.3.9074.18820

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

      Send mail to the author(s) E-mail

      Theme design by Jelle Druyts


      Pick a theme: