David Truxall

Adrift in .Net

<September 2008>
SuMoTuWeThFrSa
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011


Navigation

Other Good Blogs

My Other Articles on CodeProject

Subscriptions

News

Day of .Net October 18, 2008 - Be there!
View David Truxall's profile on LinkedIn

Post Categories



Migration Issues (RSS)

Migration Issues
Sql Server Fix Logins

Sometimes when copying databases, for instance from production down to development, the user accounts become dysfunctional. The database login no longer matches the overall server login. To re-synchronize them use:

exec sp_change_users_login auto_fix, 'someusername'

posted Tuesday, June 05, 2007 3:12 PM by davetrux with 0 Comments

Vista and Visual Studio 2003 - Not Supported

Now that Vista has gone RTM, lots of us are trying to decide when to upgrade. Here is something I have not seen much mention of:

Visual Studio 2003 is not supported in Vista.

This is going to hold back adoption on my work machine. I'm a consultant, I have to do work on whatever platform the client is using, which unfortunately is VS 2003 sometimes. Is VS 2003 going to be relegated to life in a virtual machine from now on?

posted Thursday, November 09, 2006 12:42 PM by davetrux with 0 Comments

Whidbey Beta 1 to Beta 2 Migration with Typed Datasets

Today we are migrating my project from Whidbey Beta1 to Beta 2 (if you know why this is happening today, go ahead and laugh with us), and our biggest hurdle so far is Typed Datasets.

We used dozens of XSD schemas to create typed datasets. Of course, Beta 2 no longer gives a menu option for creating a typed dataset directly from a schema (see this post  in the Fedback Center for Visual Studio). The prospect of converting to the Dataset type of schema was daunting, and moving to the command line for xsd.exe was not going over so well either.

We did discover, however, that you can still generate the dataset using the IDE. In the properties of the XSD file, you can set the custom tool to MSDataSetGenerator. Then you can right-click the XSD file and choose Run Custom Tool. The IDE generates the code for the dataset. Whew!

posted Friday, July 01, 2005 9:25 AM by davetrux with 0 Comments

Burned by Trace

I found out the hard way that when using the trace on an ASP.Net page, the interaction of the trace observer is not totally separate from the page. I am working on a page where performance is a big issue, so I have been using Trace extensively to find the weak spots and shore them up. Essentially the page is searching both the Indexing Service and an Oracle database and finding where the two datasets intersect. Because the results are a grid of links, the user can click the links and then use the Back button to return to the results. Of course I was getting the dreaded “Warning: Page has Expired” message after using the back button. The page with the grid is the result of an HTTP post, so the post has expired. Clicking the Refresh button was the only way to get the data back initially. This is bad, as the page already was having performance problems, so rendering it again was not really an option. So I tried setting the page caching options to this:

<%@ OutputCache Duration="120" VaryByParam="None" Location="Client"%>

This should cause the page to cache on the client. No dice. No matter what I set, the http_cache_control header always reported “no-cache” in the trace results. I tried making the header changes in code. Again, no change. Still reporting “no-cache”. The simple solution to the problem is to turn off tracing on the page. Well, it turns out that with Trace=”true” in the @Page directive, the http_cache_control header is set to “no-cache” no matter what. When the Tracing is off, the “Warning: Page has Expired” message disappears and the page is back in control of setting the headers.

Also, a related tidbit I discovered when trying to solve this is that the page timeout is essentially set to infinity when compiling in debug mode.

posted Monday, March 29, 2004 6:07 AM by davetrux with 0 Comments

Query the Indexing Service with Ixsso and ASP.Net
As I am continuing to migrate our ASP app to ASP.Net, it has finally come time to address the Indexing Service search. It's a big feature in the application, and the transition of this piece needs to be seamless. We want to stick with Ixsso for the Indexing Service as opposed to using the Oledb driver. Ixsso is considered to be the faster of the two technologies, even using COM interop (See various of Hilary Cotter's comments in microsoft.public.inetserver.indexserver). Code snippets for using Ixsso with ASP.Net are pretty sparse compared to using Oledb, so I figured I should post mine.  First, I used the IDE to create a reference to the ixsso Control Library dll and let the IDE make the .Net wrapper for the COM object (christened Cisso by the IDE).

Imports Cisso
Imports System.Security.Principal
Imports System.Data.OleDb

 

Private Function GetIndexResults(ByVal Query As String) As DataTable Dim Q As New CissoQueryClass Dim util As CissoUtilClass Dim da As New OleDbDataAdapter Dim ds As New DataSet("IndexServerResults")
Q.Query = Query Q.SortBy = "rank[d]" Q.Columns = "filename, rank, write" Q.Catalog = "query://DocumentServer/Resumes" Q.MaxRecords = 1000 util.AddScopeToQuery(Q, "\", "deep") Q.LocaleID = util.ISOToLocaleID("EN-US") Dim impContext As WindowsImpersonationContext = impersonateAnonymous() da.Fill(ds, Q.CreateRecordset("nonsequential"), "IndexServerResults")
Q = Nothing util = Nothing impContext.Undo()
Return myDS.Tables("IndexServerResults")
End Function

The impersonateAnonymous function is described in a previous post of mine. In our case the anonymous user on the machine has appropriate privledges to query the remote Indexing Service, but the ASP.Net worker process does not so impersonation is in order for the function. That part is probably optional depending on the situation. The rest of it is not very tricky. I tried to fill the DataTable directly without the DataAdapter, but that didn't work. The CreateRecordset function of the CissoQueryClass returns an ADO recordset and I couldn't find a cast that worked. The DataAdapter seems to be doing the casting work during the call to Fill.

posted Wednesday, March 03, 2004 1:12 PM by davetrux with 0 Comments

Sharing Timeout Management with ASP.Net and ASP

I am in a situation where my application is mixed classic ASP and ASP.Net. I am currently migrating the classic ASP app page-by-page into ASPX as I am developing new functionality. When I have to touch an old page, I convert it.

In an attempt to make them appear to be one app to the user, I need to manage the timeout of the two applications to appear as one. The classic ASP app was using Session variables for this, but obviously that would not work easily in a mixed environment. Luckily, the ASP app is not heavily dependent on Session variables; it only uses a few that are set during login, and a couple on particular pages. So after logging in the login redirects to a classic ASP page to set the few necessary Session variables, and that page redirects to the home page.

  1. Login using the ASPX login page
  2. Create a cookie containing context
  3. Redirect to asp page setting session variables
  4. Redirect to ASPX home page

Initially, I thought it would be easy to manage the timeouts, just use the cookie generated by the ASPX login page. The classic ASP pages can check the cookie and update its expiration if needed. Of course, it was not that simple. The cookie that is created by the ASPX pages contains the authentication ticket generated by the current http context. Its expiration is essentially the same as the cookie, based on the time set in web.config. The problem lies with the classic ASP pages. They can update the cookie’s expiration, but not the ticket. If a user spends too much time using classic ASP pages, the ticket in the cookie will be expired next time the user visits an ASPX page, even if the cookie is good. The ASPX pages consider a user timed out if either the cookie has expired or the ticket has expired. They will need to login again without actually timing out simply due to using classic ASP pages for a little too long.

My solution results from the ratio of classic ASP to ASPX pages. Right now it is about 5 classic ASP per ASPX page. Using this ratio I changed the authentication ticket timeout to be 5 times as long as the cookie timeout. In order to make this work the ASPX application needs to manage the cookie created by ASPX pages instead of allowing it to occur manually. At the login page, I allow the ASPX cookie to be created as normal using my own CreateAuthCookie.

Public Shared Function CreateAuthCookie(ByVal UserID As String) As HttpCookie
    Const TicketLife As Double = 4
    Dim Timeout As String = ConfigurationSettings.AppSettings("Timeout").ToString
Dim principalText As String Dim buffer As New IO.MemoryStream Dim formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
    formatter.Serialize(buffer, HttpContext.Current.User)
    buffer.Position = 0
    principalText = Convert.ToBase64String(buffer.GetBuffer())
    'create a forms ticket
Dim ticket As New FormsAuthenticationTicket(1, HttpContext.Current.User.Identity.Name, _
DateTime.Now, DateTime.Now.AddMinutes(Double.Parse(Timeout) * TicketLife), _
False, principalText)

    'Encrypt the ticket
    Dim encTicket As String = FormsAuthentication.Encrypt(ticket)
    'This is the cookie used by both ASP and ASP.Net, ASP never retrieves the value
    Dim TheCookie As New HttpCookie(FormsAuthentication.FormsCookieName)
    TheCookie.Path = FormsAuthentication.FormsCookiePath
    TheCookie.Value = encTicket
    TheCookie.Expires =    DateTime.Now.AddMinutes(Double.Parse(Timeout))

    Return TheCookie
End Function

In the Global.asax, I added code to take the cookie, get the ticket from it and use the ticket to set the HttpContext.Current.User and update its expiration if necessary. If the cookie or the ticket has expired here it will automatically redirect to the login page as a function of ASP.Net.

Private Sub Global_AcquireRequestState(ByVal sender As Object, ByVal e As EventArgs) _
Handles MyBase.AcquireRequestState Dim cookie As HttpCookie = Request.Cookies.Get(FormsAuthentication.FormsCookieName) If Not cookie Is Nothing Then 'Cookie found, decrypt the value and recreate the authentication ticket
' and user context for the page
Dim ticket As FormsAuthenticationTicket Try If cookie.Value = "" Then
'For some reason the cookie exists but there is no value,
' remove the cookie try again
cookie.Expires = DateTime.Now.AddMinutes(-15) Response.Redirect("../login/login.aspx", False) Else ticket = FormsAuthentication.Decrypt(cookie.Value) End If FormsAuthentication.RenewTicketIfOld(ticket) Dim buffer As New IO.MemoryStream(Convert.FromBase64String(ticket.UserData)) Dim formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter HttpContext.Current.User = CType(formatter.Deserialize(buffer), IPrincipal) Catch ex As Exception
'Could not set the ticket, remove the cookie cookie.Expires = DateTime.Now.AddMinutes(-15) Response.Redirect("../login/login.aspx", False) End Try End If End Sub

All my ASPX pages inherit from my own base page instead of System.Web.UI.Page. In the PreRender event for my base page my CreateAuthCookie gets set again and added to the Response. My base page has already taken the UserID from the HttpContext and set it as a page property.

Private Sub Page_PreRender(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.PreRender Dim AuthCookie As HttpCookie = CreateAuthCookie(Me.User_ID.ToString) Response.Cookies.Add(AuthCookie) End Sub

The classic ASP pages use an include file that just increments the cookie timeout. It also checks the status of the ASP session and resets it if the cookie is still good.


Dim xQString if Request.QueryString <> "" then 
xQString = "?" & Request.QueryString
end if
If
Request.Cookies("EnCoreUser") = "" then
'No cookie, session expired
Session.Abandon
Response.Cookies("EnCoreUser").Expires = DateAdd("n", -15, Now())
response.redirect "../login/login.aspx?ReturnUrl=" & _
Server.URLEncode(Request.ServerVariables("URL") & xQString)
else
'Got aspx cookie, check asp session
if Session("SessionId") <> Session.SessionID then
if Request.Cookies("asp") = "" then
response.redirect "../login/login.aspx?ReturnUrl=" & _
Server.URLEncode(Request.ServerVariables("URL") & xQString)
else
'Cookie is good but classic ASP session ended. Recreate the
' session without forcing another login.
Response.Redirect "../login/verify.asp?userid=" & user_id & "&url=" & _
Server.URLEncode(Request.ServerVariables("URL") & xQString)
end if
else
'All is well, so reset the cookie
Dim sTempx sTempx = CStr(Request.Cookies("EnCoreUser"))
Response.Cookies("EnCoreUser").Path = "/"
Response.Cookies("EnCoreUser").Expires = DateAdd("n", 35, Now())
Response.Cookies("EnCoreUser") = sTempx
end if
end if

As the ratio classic ASP pages to ASPX pages changes, all I need to do is reduce the multiplier to shorten the ticket length accordingly. Eventually, of course, all this work will get tossed out when there are no more classic ASP pages.

posted Wednesday, January 28, 2004 10:21 AM by davetrux with 0 Comments

Business Objects Dead?

There a fascinating discussion going on at Tim Sneath's blog about the functionality of the business layer moving to compiled stored procedures in Yukon. At least in my project, we have been doing that very thing and struggled with the n-Tier issue as a result. In our case, the database is Oracle 8i, and the application is/was ASP, which we are now converting to .Net. We have some very complex business logic encapsulated in PL/SQL stored procedures. There were two concrete reasons for the decision:

  1. The amount of data that would need to be transferred was huge.
  2. Oracle is more efficient than ASP code at many of the operations involved.

With ADO.Net, some of the ineffieciency may be addressed, but the database is designed for efficiency at certain operations that ADO.Net won't be able to match.

We did not need to approach this from a scalability issue, as the app receives hundreds of hits per hour, not thousands or more. I still think it will scale OK as your business objects will have much shorter life spans and you can still pool and queue database connection objects if needed due to long-running stored procedures.

posted Monday, October 06, 2003 5:57 AM by davetrux with 0 Comments

Data Access Application Block and Oracle

I read about the Data Application Block  yesterday and was intrigued, although for the life of me I cannot remember where I read about it originally to pass along some credit. So I checked it out and it is very nice and all, but alas my project uses Oracle not SQL Server. Initially I thought about porting it to Oracle, but I figured that it has already been done. So I did a little Googling and voila!, Microsoft themselves had already done the work in the Nile 3.0 demo application. Sadly, it was in C# and my current project is using Oracle and VB.Net. So now I am back to porting.

posted Friday, September 19, 2003 5:30 AM by davetrux with 0 Comments

Migrating our ASP app to .Net

We are migrating an ASP app to ASP.Net, but not all at one time as my business customers within the company won't pay for that kind of time all at once. So we are migrating piece-by-piece as we develop new functions within the app. Our plan is to develop all new pages using .Net, and convert classic ASP pages as we have to touch them due to new development. To get the remaining pages converted, we are just going to squeeze them in as often as possible along with the new development, mostly on a one or two at a time basis. So probably of the next 6-12 months the ASP and ASP.Net applications will coexist and appear to the users to be one application.

Right now, we have done what we considered the basic conversion necessary to implement our plan:

  • Convert the login process to .Net. We are using Forms authentication since users are checked from our own database. We may migrate this to LDAP sometime in the future. My company uses Novell Netware for network login and GroupWise for email. I would love to hear from anyone who has a web app that can create appointments in GroupWise!!
  • Move frequently used Session variables to cookies. Luckily, we were not using lots of Session variables in the classic ASP. We encrypt all the data written to the cookies so spoofing is harder. We are currently not a web farm, but that is also in our future so the Session variables need to go anyway.
  • Create a common time-out scheme between the applications using a cookie. The ASP app times out after 35 minutes of inactivity for what the HR folks call “security“, as the app contains lots of personal information about both employees and non-employees.
  • Convert common functions to .Net (like checking user roles, encryption, database access, search engine, etc.)
  • Convert ASP includes for page structure into .ascx files.

Of course, none of this has gone into production yet (sigh...). It is on the test sever and hopefully will roll out by the end of the month.

posted Tuesday, September 02, 2003 10:22 AM by davetrux with 0 Comments




Powered by Dot Net Junkies, by Telligent Systems