Upgrading to 2005 Continuing To Be A Pain

I decided to go with Scott Gu’s suggestion to use Web Application Projects to help ease the conversion for 2003.

I will agree that this is a much better way to convert your project than to turn it into a Web Site Project, but there are still lingering problems.

In one of my projects the web page and code behind have somehow become lost.  The code behind pages can’t see their controls, which are placed in some mystery file thanks to the new Partial Class feature.

I tried ranaming the files, I tried cutting and then replacing the HTML that defines the controls, the only thing I found that works is to totally delete the file and recreate it exactly the same way.  What a pain.

The “What a pain” concept is the only constant in this process.

I am still not sure what is going on with project references. 

As far as I see, if there is a DLL in the bin directory, you don’t need a reference to that DLL.  But as soon as you clean out your bin, your project will break with error messages that are nothing like “Are you missing a reference?” because, of course you are, VS.Net just removes them all the time w/o asking you! 

There must be some new paradigm with how you are supposed to work with references, projects, and solutions, because trying to do it like you would in vs.net 2003 is causing a ton of problems.

Update: Almost as if VS was getting back at me, as soon as I posted this it took a crap and crashed.  🙂

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. 

You can take this code and run it as a console app to see the results, which should be:

SetNothingByVal: Object was not cleared
SetNothingByRef: Object was cleared
ChangeFieldByVal: Object WAS modified
ChangeFieldByRef: Object WAS modified
SetStructToNothingByVal was NOT able to null out the structure
SetStructToNothingByRef was able to null out the structure
SetStructToNothingByVal was NOT able to change the structure
SetStructToNothingByRef was able to null change structure

 

Imports Microsoft.VisualBasic
Imports System
Imports System.Collections

Public Class SomeObject
Public MyField As String
End Class

Public Structure SomeValueType
Public MyField As Integer
End Structure

Public Module MyModule

Sub Main()
RL()
TryToNullAnObject()

TryToModifyObject()

TryToNullStructure()

TryToModifyStructure()
RL()
End Sub

#Region "TryToModifyStructure"
Private Sub TryToModifyStructure()
Dim s As SomeValueType
s.MyField = 1
Call ChangeStructByVal(s)
If s.MyField <> 1 Then
WL("SetStructToNothingByVal was able to change the structure")
Else
WL("SetStructToNothingByVal was NOT able to change the structure")
End If
Call ChangeStructByRef(s)
If s.MyField <> 1 Then
WL("SetStructToNothingByRef was able to null change structure")
Else
WL("SetStructToNothingByRef was NOT able to null change structure")
End If
End Sub
#End Region


#Region "TryToNullStructure"
Private Sub TryToNullStructure()
Dim s As SomeValueType
s.MyField = 1

If s.MyField = Nothing Then
WL("before we even start, we are at nothing")
End If
Call SetStructToNothingByVal(s)
If s.MyField = Nothing Then
WL("SetStructToNothingByVal was able to null out the structure")
Else
WL("SetStructToNothingByVal was NOT able to null out the structure")
End If
Call SetStructToNothingByRef(s)
If s.MyField = Nothing Then
WL("SetStructToNothingByRef was able to null out the structure")
Else
WL("SetStructToNothingByRef was NOT able to null out the structure")
End If

End Sub
#End Region


#Region "TryToNullAnObject"
Public Sub TryToNullAnObject()
Dim o As New SomeObject

o.MyField = "test"
Call SetNothingByVal(o)
If o Is Nothing Then
WL("SetNothingByVal: Object was cleared")
Else
WL("SetNothingByVal: Object was not cleared")
End If
Call SetNothingByRef(o)
If o Is Nothing Then
WL("SetNothingByRef: Object was cleared")
Else
WL("SetNothingByRef: Object was not cleared")
End If
End Sub
#End Region


#Region "TryToModifyObject"
Private Sub TryToModifyObject()
Dim o As New SomeObject
o.MyField = "test"
Call ChangeFieldByVal(o)
If o.MyField = "test" Then
WL("ChangeFieldByVal: Object was not modified")
Else
WL("ChangeFieldByVal: Object WAS modified")
End If
Call ChangeFieldByRef(o)
If o.MyField = "test" Then
WL("ChangeFieldByRef: Object was not modified")
Else
WL("ChangeFieldByRef: Object WAS modified")
End If
End Sub
#End Region


#Region "Functions to do all the testing"
Public Sub SetNothingByRef(ByRef o As SomeObject)
o = Nothing
End Sub
Public Sub SetNothingByVal(ByVal o As SomeObject)
o = Nothing
End Sub

Public Sub ChangeFieldByRef(ByRef o As SomeObject)
o.MyField = "changed"
End Sub
Public Sub ChangeFieldByVal(ByVal o As SomeObject)
o.MyField = "changed"
End Sub

Public Sub SetStructToNothingByRef(ByRef o As SomeValueType)
o = Nothing
End Sub
Public Sub SetStructToNothingByVal(ByVal o As SomeValueType)
o = Nothing
End Sub

Public Sub ChangeStructByRef(ByRef o As SomeValueType)
o.MyField = 123
End Sub

Public Sub ChangeStructByVal(ByVal o As SomeValueType)
o.MyField = 123
End Sub
#End Region


#Region "Helper methods"

Sub WL(ByVal text As Object)
Console.WriteLine(text)
End Sub

Sub WL(ByVal text As Object, ByVal 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


 

 

From Asp.net 1.1 to 2.0: Parser Error – Could not load type 'xyz.Global'

As we were upgrading to run ASP.Net 2.0, we ran into this wonderful problem.  Your code seems to run fine until you push it to a server and you get this error:

 Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Parser Error Message: Could not load type ‘xyz.Global’.
Source Error:

Line 1:  <%@ Application Inherits="xyz.Global" Language="VB" %>

Source File: /global.asax    Line: 1


Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.42

 

There are 2 things I had to remember to do to get this to work.

1) We use a domain user for the aps.net worker process, so our site can access UNC files across the network.  In order for this user to have the ability to compile the app, you have to give them full rights to: c:WINDOWSMicrosoft.NETFrameworkv1.1.4322 and if you start running your apps in .net 2.0, you need to do the same for c:WINDOWSMicrosoft.NETFrameworkv2.0.50727.

2) If you have any web apps running in 1.1, there is a good chance that even thought you changed the iis setting to asp.net 2.X, you are still running against an app pool that is shared with another site using asp.net 1.1.  So, just create a new app pool, and have your newly 2.0 site setup to use that app pool.

Problem solved!

VS.Net 2005, Projects, Solutions, and References: What was MS thinking??? This SUCKS!!!!

This is really shocking (and very disappointing) to me.

I had the task of upgrading the code base at Walsh Construction from .net 1.1 to 2.0 and putting it all in a source control database.

I had been getting a lot of totally random build problems, and I started wondering: Where does it store my references?

ASP.Net Web Sites projects don’t have a vbproj or csproj file anymore, so where is it storing the fact that I want this website to have a references to a given DLL or a given project in my solution?

I found that the answer is that the project references are stored in the solution file! 

If you open up the solution file you will find lots of stuff like this:

ProjectSection(WebsiteProperties) = preProject
ProjectReferences = "{E050AEA3-6DCA-4DE8-936F-5A8B14A912B9}|MyReferencedAssembly.dll;

This is kinda stupid.

Non-website projects keep a list of their references in their project file.

Websites keep SOME reference info in their web.config, although I think that is only for DLLs that are in the GAC.

Anyway on to the list of things that truly suck about how this works:

1)  When you add a reference from a web project to a DLL, the DLL is copied to the Bin directory right then, as opposed to when you do the build.  I bet it does it at build-time as well, but what really sucks is that you can have a situation where WebSiteA references ComponentA which references DataAccessLayerA.  WebSiteA will have DataAccessLayerA.dll in it’s bin directory, then if you go to add a references from WebSiteA to DataAccessLayerA, it will say “Oh you already have a reference” when you really don’t, and if you try to build it won’t work until you go delete that dll from your bin and add the reference.

2)  I have been unable to open some projects without opening the entire solution that I joined them too at one point.  Basically as I was converting all our projects over to 2003 I wanted to also change them from DLL references to project references.  So I created a solution with ever project and website we have in .net.  To illustrate my problem, I added a project to the solution called IAmABogusProject with 1 class and 1 static method.  No one uses this class, no projects have a reference to this project, and this project has no references to any other projects.  Yet, if I go click on the vbproj file for this project, it loads up my solution file with every single project.  I tried creating another solution and adding it to that one to see if it would open the new solution when I tried to reopen the project but no luck, it opened original solution with every application again!! WTF!!

3) This is the worst of the list.  If you have a project in a solution that is referenced by some other projects and you remove that project from the solution, guess what happens?  In 2003 it would remove the project and all the referencing projects would show a missing reference icon.  In 2005 it checks out all the referencing projects and removes the reference!!!  Are you kidding me???  For the cherry on top, you have to then manually add all the references back after you add the project back into the solution, and of course you get all kinds of weird bugs, none telling you that you are missing an assembly reference.  Totally stupid.   This is a bug, see Update3 at the bottom.

I am really pissed about this.  Why do MS product upgrades frequently come with a “What were they thinking?” tag? 

Maybe the roll of the solution has changed or something, but this is going to really piss me off working like this day to day.

I have already had something happen where all my website projects that I had already added to source control lost their binding.  Great….

Update1:  I am continuing to have problems with my web project “losing” references that I have to keep setting.  What a pain this is becoming!

Update2: Scott Gu from Microsoft (http://weblogs.asp.net/scottgu) suggested that I give the Web Application projects a try.  I had tried them once before when in beta and remembered there was something that was a show stopper at the time.  I don’t remember exactly what, maybe the designer didn’t work?  Anyway, that could solve a few of my issues, but this whole thing of not being able to open a project without a solution getting opened, and the thing where VS removes references from projects (even if they are under source control) if you remove the project from a solution is crazy.

Update3: Well thank God, someone from Microsoft let me know that this thing with removing a project causing references to disappear is actually a bug: http://www.chrismay.org/2006/04/19/VS2005RemoveProjectLoseReference.aspx 

Running ASP.NET Development Server Without Virtual Path, From Root

I had been looking for a way to get the asp.net development server to run w/o a virtual directory settings.  It’s really very stupid and short sighted to not enable this.  Just about every project I have ever worked on has some paths coded into the HTML that are based on / being the root, not the application root.  Stupid.

 

Anyway, ScottGu posted these steps on his site, and it works.  Not bad!

Step 1: Select the “Tools->External Tools” menu option in VS or Visual Web Developer.  This will allow you to configure and add new menu items to your Tools menu.

 

Step 2: Click the “Add” button to add a new external tool menu item.  Name it “WebServer on Port 8080” (or anything else you want).

 

Step 3: For the “Command” textbox setting enter this value: C:WINDOWSMicrosoft.NETFrameworkv2.0.50727WebDev.WebServer.EXE (note: this points to the web-server that VS usually automatically runs).

 

Step 4: For the “Arguments” textbox setting enter this value: /port:8080 /path:$(ProjectDir)

 

Step 5: Select the “Use Output Window” checkbox (this will prevent the command-shell window from popping up.

 

 Once you hit apply and ok you will now have a new menu item in your “Tools” menu called “WebServer on Port 8080”.  You can now select any web project in your solution and then choose this menu option to launch a web-server that has a root site on port 8080 (or whatever other port you want) for the project.

 

You can then connect to this site in a browser by simply saying http://localhost:8080/.  All root based references will work fine.

 

Step 6: The last step is to configure your web project to automatically reference this web-server when you run or debug a site instead of launching the built-in web-server itself.  To-do this, select your web-project in the solution explorer, right click and select “property pages”.  Select the “start options” setting on the left, and under server change the radio button value from the default (which is use built-in webserver) to instead be “Use custom server”.  Then set the Base URL value to be: http://localhost:8080/

Expert VB 2005 Business Objects eBook

Here is the link to get the book in beta:
http://www.apress.com/book/bookDisplay.html?bID=10090

Expert VB 2005 Business Objects takes you from an opening discussion of logical architectures to detailed n-tier deployment options using the CSLA .NET Framework. Rockford provides enough understanding and detail for you to take this approach to your own projects, as many developers have already done.

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

Indents Fixed!

Well a little tweaking of the code that does the generation of the formatted code, and it now produces what I want:

        Public Shared Function AddTOQueryString(ByVal URL As String, ByVal Key As String, ByVal Value As String) As String
Dim RegExp As New System.Text.RegularExpressions.Regex(Key & "=.*?(&|$)")
Dim Match As System.Text.RegularExpressions.Match = RegExp.Match(URL)
If Match.Success Then
Return RegExp.Replace(URL, Key & "=" & Value & Match.Groups(1).ToString)
ElseIf URL.IndexOf("?") > 0 Then
Return URL & "&" & Key & "=" & Value
Else
Return URL & "?" & Key & "=" & Value
End If
End Function
        /// <summary>Gets or sets the RSS version to write.</summary>
        /// <exception cref="InvalidOperationException">Can't change version number after data has been written.</exception>
        public RssVersion Version
        {
            get { return rssVersion; }
            set
            {
                if(wroteStartDocument)
                    throw new InvalidOperationException("Can't change version number after data has been written.");
                else
                    rssVersion = value;
            }
        }

I am not sure that I like what it does with literal strings.  I will probably want to change that.

I am also now convinced that it will not due for formatting Javascript.  J# just doesn’t share enough similar attributes.  This tool also doesn’t support XML (or HTML), which would be a nice thing too.

This converter looks pretty sweet.  You can include your regions and it will let you keep them collapsed and then expand via javascript, excellent.

I could also just wire up the implementation I already have to deal with HTML and Javascript.

We will see… for now this will do.

HttpFilters, HttpModules, and HttpWastedABunchOfTime

I was just about to make a post talking about the switch over to dasBlog.  I was going to talk about what I liked and didn’t like and whatever, but mostly I was going to talk about the work I have been putting in on writing code that will filter out code and format it nicely.

I wrote and tested an HttpModule which loads a Reponse Filter that parses the Html looking for <code> tags and formats the code inside those nicely.

So I go to write my first post, and I am looking for a hyperlink button in the texteditor, but instead I see this icon that look like a C# file.  “No, I did not just waste all that time” I thought. 

public bool IsTimeWasted(String name){
    return true;
}

Public Function IsWasted(ByVal time As TimeSpent) As Boolean
  If time IsNot Nothing Then
    Return True
  Else
    Return False
  End If
End Function

var s;
s = ‘asdf’;
document.getElementById(“asdf”); /* comment */

SELECT * FROM
ThingsToDo
WHERE
WastedTime <> 1
AND
Task = ‘Writing HttpFilter’

0 rows returned

So you can see I basically wasted my time doing all that.

This tool doesn’t provide an HTML code type, and I used J# in place of Javascript, but it works ok I guess.

The on thing it is really lacking is that it doesn’t maintain indents!?!?  I manually restored the indents above, otherwise my vb code would look like this:

Public Function IsWasted(ByVal time As TimeSpent) As Boolean
If time IsNot Nothing Then
Return True
Else
Return False
End If
End Function

Which is weird, b/c it looks fine in the preview window… I will have to look into that.