October 2004 - Posts

CreateProcessAsUser

Here is a solution you can use in rare circumstances and with caution. Comments are more then welcomed.

Anytime someone approaches me with a design requiring the creation of a server side process – I flinch. Spinning up a process on the server is something to avoid. Having said that, I found it useful in a small Intranet applications (a build engine) to put a web service / ASP.NET interface in front of some command line CM tools. The interface is available to a small number of trusted individuals.

I wanted to run these processes with the identity of the client, but this poses a problem. The Process class in System.Diagnostics can start a new process, but the process always inherits the security context of the parent process. Even if the ASP.NET thread invoking the Start method is impersonating a client, the Process still starts with the ASP.NET worker process credentials.

Enter .NET 2.0, which includes the User, Domain, and Password properties on the ProcessStartInfo type. In .NET 2.0 you can start a process under a different set of credentials. The catch is having a password to give. I don't want the burden of managing passwords when there is a domain controller handy.

Having found no solution in the framework, the next step was to look into the Win32 API. There are four basic functions to start a process: CreateProcess, CreateProcessWithLogonW, CreateProcessAsUser, and CreateProcessWithTokenW. Since CreateProcess doesn’t allow an alternate identity, and one of 11 parameters to CreateProcessWithLogonW is a password, those are both out of the running.

The remaining two (CreateProcessWithTokenW and CreateProcessAsUser) both accept a token instead of a username and password, so these look promising. CreateProcessWithTokenW allows greater fine tuning of the logon type and creation flags, which I didn't need, so I focused in on CreateProcessAsUser.

CreateProcessAsUser accepts a user token as the first parameter. We can easily get a token representing the client we are impersonating using the WindowsIdentity class in .NET, but there still exists a problem. The token will be an impersonation token - which isn’t good enough for CreateProcessAsUser. However, the docs mention that you can use DuplicateTokenEx to convert an impersonation token into a primary token. The code at the end of this post demonstrates the incantations.

Note: The calling process needs SeAssignPrimaryTokenPrivilege and SeIncreaseQuotasPrivilege privileges, which the NETWORK SERVICE account has by default on Windows 2003.

Note: I’m not sure how far the ‘primary token’ yielded by DuplicateTokenEx can go. Could I effectively delegate without delegation enabled? I wouldn't think so. Must experiment. Anyone know?

Note: If you are thinking of using this to launch an interactive GUI application on the server – don’t. The process will start in a non-interactive window station and remain invisible but consuming memory.

private void CreateProcessAsUser()
{
   IntPtr hToken = WindowsIdentity.GetCurrent().Token;         
   IntPtr hDupedToken = IntPtr.Zero;        
   
   ProcessUtility.PROCESS_INFORMATION pi = new ProcessUtility.PROCESS_INFORMATION();
   
   try
   {
      ProcessUtility.SECURITY_ATTRIBUTES sa = new ProcessUtility.SECURITY_ATTRIBUTE();
      sa.Length = Marshal.SizeOf(sa); 
 
      bool result = ProcessUtility.DuplicateTokenEx(
            hToken, 
            ProcessUtility.GENERIC_ALL_ACCESS,
            ref sa, 
            (int)ProcessUtility.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
            (int)ProcessUtility.TOKEN_TYPE.TokenPrimary, 
            ref hDupedToken
         );
   
      if(!result)
      {               
         throw new ApplicationException("DuplicateTokenEx failed");
      }
 
 
      ProcessUtility.STARTUPINFO si = new ProcessUtility.STARTUPINFO();
      si.cb = Marshal.SizeOf(si);
      si.lpDesktop = String.Empty;           
 
      result = ProcessUtility.CreateProcessAsUser(
                           hDupedToken, 
                           @"",
                           String.Empty,
                           ref sa, ref sa, 
                           false, 0, IntPtr.Zero, 
                           @"C:\", ref si, ref pi
                     );
 
      if(!result)
      {  
         int error = Marshal.GetLastWin32Error();
         string message = String.Format("CreateProcessAsUser Error: {0}", error);
         throw new ApplicationException(message);
      }
   }
   finally
   {
      if(pi.hProcess != IntPtr.Zero)
         ProcessUtility.CloseHandle(pi.hProcess);
      if(pi.hThread != IntPtr.Zero)
         ProcessUtility.CloseHandle(pi.hThread);
      if(hDupedToken != IntPtr.Zero)
         ProcessUtility.CloseHandle(hDupedToken);      
   }
}

ProcessUtility…

public class ProcessUtility
{
   [StructLayout(LayoutKind.Sequential)]
      public struct STARTUPINFO
   {
      public Int32 cb;
      public string lpReserved;
      public string lpDesktop;
      public string lpTitle;
      public Int32 dwX;
      public Int32 dwY;
      public Int32 dwXSize;
      public Int32 dwXCountChars;
      public Int32 dwYCountChars;
      public Int32 dwFillAttribute;
      public Int32 dwFlags;
      public Int16 wShowWindow;
      public Int16 cbReserved2;
      public IntPtr lpReserved2;
      public IntPtr hStdInput;
      public IntPtr hStdOutput;
      public IntPtr hStdError;
   }
 
   [StructLayout(LayoutKind.Sequential)]
      public struct PROCESS_INFORMATION
   {
      public IntPtr hProcess;
      public IntPtr hThread;
      public Int32 dwProcessID;
      public Int32 dwThreadID;
   }
 
   [StructLayout(LayoutKind.Sequential)]
      public struct SECURITY_ATTRIBUTES
   {
      public Int32 Length;
      public IntPtr lpSecurityDescriptor;
      public bool bInheritHandle;
   }
 
   public enum SECURITY_IMPERSONATION_LEVEL
   {
      SecurityAnonymous,
      SecurityIdentification,
      SecurityImpersonation,
      SecurityDelegation
   }
 
   public enum TOKEN_TYPE
   {
      TokenPrimary = 1, 
      TokenImpersonation
   } 
 
   public const int GENERIC_ALL_ACCESS = 0x10000000;
 
   [
      DllImport("kernel32.dll", 
         EntryPoint = "CloseHandle", SetLastError = true, 
         CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
   ]
   public static extern bool CloseHandle(IntPtr handle);
 
   [
      DllImport("advapi32.dll", 
         EntryPoint = "CreateProcessAsUser", SetLastError = true, 
         CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)
   ]
   public static extern bool 
      CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, 
                          ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, 
                          bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment,
                          string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, 
                          ref PROCESS_INFORMATION lpProcessInformation);
 
   [
      DllImport("advapi32.dll", 
         EntryPoint = "DuplicateTokenEx")
   ]
   public static extern bool 
      DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess, 
                       ref SECURITY_ATTRIBUTES lpThreadAttributes,
                       Int32 ImpersonationLevel, Int32 dwTokenType, 
                       ref IntPtr phNewToken);
}
posted by scott with 29 Comments

Resolving SSL Error Messages With Reporting Services

A couple people have left comments here about running into the following error in Reporting Services:

The underlying connection was closed: Could not establish secure channel for SSL/TLS.

There are a number of reasons this error can occur, so it will involve some digging to get to the root cause. Most of the problems revolve around a failure to verify the SSL certificate on the report server. You might see the error because:

  • The name for the certificate does not match the name of the server
  • The certificate has expired or is considered invalid.

A good way to troubleshoot is to browse to the report server with Internet Explorer (https://machinename/reportserver) and see if IE complains.

There are also some less obvious reasons the error might occur. For example, the system time might be incorrect - making it appear as if the certificate has expired (when it has not), or has not yet been created (a certificate from the future!). Set the clock correctly.

If IE likes the cert, there might be a configuration issue. The URL used by the Report Manager to communicate with the ReportServer is found in a file under the Report Manager directory by the name of RSWebApplication.config. Find the <ReportServerUrl> element and make sure the URL matches the name on the certificate (which will match the name of the server). Hint: using https://localhost/reportserver is not going to work.

If you are in an environment that does not require SSL, and you are 100% positive you want payroll reports to cross the ether in plain text, you can find the RSReportServer.config file in the ReportServer directory and set SecureConnectionLevel Value=”0”.

I’m sure this is not the exhaustive list, but hopefully it will help someone out.

posted by scott with 1 Comments

Success Is Sweet!!

My impatience rushed me into tempting fate. Instead of waiting for the full moon to rise tomorrow evening, I started my BizTalk install Sunday afternoon. (There is also a lunar eclipse tomorrow evening - a blood moon, visible everywhere except from Australia - sorry John).

I’m happy to say the installation went swimmingly. The HelloWorld Orchestration sample spit out an invoice, and much celebration ensued.

So, what are the keys to a successful BizTalk installation? Let me tell you what worked for me.

1: Read John Elliot’s incredibly clever and Shakespearean inspired ‘Installing BizTalk 101’. (Sorry, that link is no longer available. Perhaps John will send me the contents....)

2: Follow Luke Nyswonger’s “The QuickStart Guide to Installing & Configuring Microsoft BizTalk Server 2004” step by step. Let me quote prose from Ray Bradbury’s well-known short story “A Sound Of Thunder”:

Stay on the path. Don’t go off it. I repeat. Don’t go off it. For any reason! If you fall off, there’s a penalty.”

The following steps are optional, but comforting if you are the suspicious sort.

3: I took Anil’s suggestion and added a candle to the mix. The candle I used carried the delicate scent of a blueberry harvest. I feel fairly confident in recommending any fruit scented candle, but avoid vanilla, cinnamon, and wild honysuckle.

(Note: be sure not to use those cheap little birthday candles because the process takes a while. You’ll need to sustain a good 3-6 hour burn. Also, remember to check the fire codes first if you are conducting the ritual inside a place of business).

4. I also placed a small Ganesh (remover of obstacles) figurine on the target machine. Figure 1 will give you an idea of how to arrange the candle and charm to maximize your chances of success.

Figure 1: BizTalk installations should place candles on the left - good luck charms on the right.

P.S. In all seriousness, thanks to Lee and Luke for offering to help out and giving me some pointers. 

posted by scott with 6 Comments

I Didn’t Expect These Features

What do MARS and the new Edit and Continue features have in common?

  • Both were technically difficult to implement
  • I never expected either to show up.

Whenever discussions cropped up about these features the pushback always seemed to indicate both required major disruptions to the lowest level code you can imagine, and possibly changing the gravitational constant. Now these features are here in beta.

Edit and continue (E&C) allows a developer to edit code in a running application and continue running the updated application without having to stop, compile, and launch the debugger again. It’s amazing the range of responses this feature generates. Jonathon Goodyear proclaimed it would be a colossal mistake for Microsoft to not ship this feature in 2005. Sam Gentile (who is a C# MVP, just in case he didn’t tell you), feels E&C will ruin software development.

In the end these discussions always collapse into some sort of three way language war between people who use semicolons, people who don’t use semicolons, and people who use Smalltalk. It’s odd how that happens. I wonder what happens inside the meeting rooms around Redmond when this feature came up for discussion?

I don’t see myself ever using E&C, except maybe once every two years when some weird bug crops up in a windows service with a long setup time. Given it has taken 4 or more years to work this hot potato into the runtime, I’m sure I would have picked other features I could use in day to day work and never miss E&C.

At least with E&C you can take it or leave it. MARS, on the other hand, seems to be sneaking in with an impact on anyone using the native .NET SQL Server client.

Multiple Active Result Sets (MARS) lets a client have more than one pending request on a given connection. What does this mean in code? Consider the following snippet:

SqlConnection connection = new SqlConnection("[connection string]");
connection.Open();
SqlCommand command = new SqlCommand("[query 1]", connection);
SqlDataReader reader = command.ExecuteReader();
SqlCommand command2 = new SqlCommand("[query 2]", connection);
SqlDataReader reader2 = command2.ExecuteReader();

I just ran this with the October CTP of Whidbey and SQL Server. The application runs without error. In .NET 1.1, however, we would see an exception:

Unhandled Exception: System.InvalidOperationException: There is already an open
DataReader associated with this Connection which must be closed first.

The Technet document introducing MARS gives explanations and use cases for where this behavior is useful, and it also mentions: “In conclusion, we can say that MARS is all about getting rid of "Connection Busy", a significant improvement to the programming model.”. It does sound attractive on the surface, but…

You can ask anyone in the ASP.NET or ADO.NET newsgroups (like Bill, for instance), and they can tell you the aforementioned exception shows up time and time again in questions. The exception is usually the first clue a new developer has that they are not closing database connections. Oh well, you say, they will just have to learn the hard way, what impact is in it for me?

For starters, make sure to read the sections on “Performance and Cost Considerations” and “MARS Deadlocks” as food for thought. Even more interesting is the MARS FAQ on Angel Saenz-Badillos blog. Suddenly, creating a SqlCommand isn’t going to be quick and relatively free (and the OleDb provider has all sorts of caveats to watch for). MARS is on by default, and there really is no way to disable the feature to recover the cost or avoid the worst case scenarios for the feature.

ADO.NET seems to be replanting new pitfalls over the old ones we left behind in ADO. Surely, there must be some driving reason for this complexity in ADO.NET.

Could it be something required to build ObjectSpaces?

posted by scott with 2 Comments

SetReportParameters

Question came in today about the SetReportParameters web service method of Reporting Services.

The name SetReportParameters is a bit misleading, and the documentation isn’t extremely clear. The method does not pass parameters to a report for rendering. Instead, the method has the same effect as modifying the parameter properties in the report designer. You can programmatically set valid values and prompt strings, etc. SetReportParameters is more of a “design time” method.

When SSRS goes to render a report, the parameter values come from one of three sources.

First, there could be a default parameter value specified in the report definition. If a default value exists SSRS will use the value, but you can override the default by passing a new parameter value using one of the techniques in the second source of parameter values.

The second source of a parameter value depends on how you access the Report Server. With URL access, you can pass a parameter value in the query string (&ParamName=Europe). If you are using the web service, then the ReportingService.Render web method accepts an array of type ParameterValue. The documentation online includes an example of how to pass the parameter values.

Finally, if there is a parameter left that does not have a default value, and you did not specify a value in the query string or in the web service call, SSRS has no choice but to prompt the user to enter a value. If you have hidden the parameter input area or the toolbar, the Report Server will throw an exception, otherwise you’ll see the TextBox and DropDownList controls appear for the user to select values.

Hope this helps…

posted by scott with 8 Comments

The Lies I Tell At Work

I’m glad you are here, gentle reader. I hope you’ve arrived in an understanding mood, because I feel compelled to unburden myself at your expense. For the last four months, I’ve practiced the art of deception at work.

You see, every few weeks our CEO brings up the topic of BizTalk Server 2004. We talk vaguely about how BizTalk might help us deploy solutions for our clients. A discussion ensues about XML and healthcare schemas. Eventually, someone will ask me if I’d had a chance to investigate the technology more thoroughly.

“Well”, I say, “the Canadian project we picked up has required more of my attention then I originally thought. I have not had a chance to dig into BizTalk yet”.

Not exactly true.

Other times I say: “I’ve been working with the statistician on algorithms for severity adjustment of patient diagnoses, but I’ll try to squeeze BizTalk into the schedule real soon”.

A little fib.

My dear reader, I’m about to give you the truth of the matter. Here is the real reason I have not devoted my research time to this marvelous product known as BizTalk Server.

I CAN’T GET THE @##@*^% PIECE OF @^*% TO INSTALL AND I’VE TRIED FIFTEEN #&#*^% TIMES AND I’M AFRAID THE BOSS WILL THINK I’M SOME SORT OF #&#**^% DIMWIT.

There. It’s off my chest. It’s in the open.

Ok, technically, it “installs”, but I’m impotent when it comes to running the configuration wizard. I’ve tried on multiple machines. I’ve tried with fewer features. Not once have I made it through ConfigFramework.exe without a severe error. BizTalk hates me, but I have a plan.

One week from today, on October 27th, will bring a full moon. I know where I can buy some chickens, and I found a 1-900 hotline with virgins who say they will do anything. In the evening of October 27th - I will try once again to install BizTalk Server 2004.

I’m feeling better now, having admitted my hideous ruse to you, dear reader. I hope you don’t think any less of me than you already did.

October 27th.

Stay tuned for details.
posted by scott with 16 Comments

Evaluating The DataBinder

I was trying to put together a quick piece of code as an example over the weekend and remembered how much I dislike using DataBinder in ASP.NET.

Let’s say a web service call gives back an array of simple objects (the sort of objects you’d see imported by a web reference):

class Parameter
{  
 public string Name;
 public string Value;
}

I wanted to dump the Parameter array to a web page as easily as possible. The following will not work.

<asp:Repeater id="Repeater1" runat="server">
   <ItemTemplate>
      <tr>
         <td>
            <%# DataBinder.Eval(Container.DataItem, "Name") %>
         </td>
         <td>
            <%# DataBinder.Eval(Container.DataItem, "Value") %>
         </td>
      </tr>
   </ItemTemplate>
</asp:Repeater>

The DataBinder, besides looking awkward, only finds public properties - it doesn’t find public fields. The quick hack to get around this is to replace the language agnostic DataBinder syntax with C# code:

<asp:Repeater id="Repeater1" runat="server">
    <ItemTemplate>
        <tr>
            <td>
                <%# ((Parameter)(Container.DataItem)).Name %>
            </td>
            <td>
                <%# ((Parameter)(Container.DataItem)).Value %>
            </td>
        </tr>
    </ItemTemplate>
</asp:Repeater>

Disadvantages:
There is a huge disadvantage in that if the Parameter class fields ever change, the code in the ASPX won’t generate an error until runtime. It’s also a problem if the ASPX moved from a C# project to a VB.NET project.

Advantages:
To me the second example looks cleaner – I can see an object and a property even through the parentheses of a cast. It’s also blazingly faster - two order of magnitude faster. In fact, in my tests the following:

<%# DataBindParameterName(Container.DataItem) %>
// in the code behind of the class:
protected string DataBindParameterName(object o)
{
    return ((Parameter)o).Name;
}

is still 300x faster than the reflection machinations DataBinder.Eval uses. Food for thought in perf critical scenarios.

posted by scott with 2 Comments

Three Things I Learned In Boston

  1. Navigating Boston with the aid of a speech enabled GPS device is about as useful as navigating Boston with the aid of a chatty 3 year old. “TURN LEFT”, the device says. Ok. Would that be the street 30° to the left or the street 60° degrees to the left? This happened more than once. Note to self: write down street names on next trip.
  2. I need to install Windows SharePoint Services and find out what all the hoopla is about. After hearing about SPS in the hallways and seeing it in a presentation, I want to learn more.
  3. It is possible to live on pizza, sushi, and diet coke for three days.
posted by scott with 5 Comments

Slides and Code From The Camping Trip

Codecamp2.zip contains the slides and code from my presentation on integrating SQL Server Reporting Services with ASP.NET.

The code includes one web project to demonstrate:

  • URL access to the report server
  • A simple demo of the ReportViewer component
  • Building a TreeView of report items with a web service call (ListChildren)
  • Examining report parameters – their valid values, type, dependencies, and state with multiple web service calls to GetReportParameters

The second project delivers a report to a second ASP.NET application (a .Text blog) via a web service call. For more information on this project, see my post: The Blog Delivery Extension.

Kudos to Thom Robbins, the other MS folks, and all of the speakers for a great weekend.

posted by scott with 1 Comments

Code Camp II

If you are coming to Code Camp 2 this weekend, I hope to see you at my talk Saturday afternoon on integrating SQL Server Reporting Services and ASP.NET. This session is not about designing reports, it’s all about integration: URL access, web services, and delivery extensions. These topics are useful for SSRS integration with any type of application, actually, but the session does focus in on particular points of pain in an ASP.NET environment. I’ve been through the pain, and I can pass along tips to make it easier for others.

At some point next week I’ll get the code examples and slide deck onto OdeToCode.com.

I can’t wait to attend the other presentations and chalk talks, they look great. There are a boat load of bloggers coming:  DonXML, Scott Watermasysk, Kent Tegels, Chris Pels, Carl Franklin, Jason Bock, Robert Hurlbut, Chris Bowen, and Sam Gentile. Who did I miss? There is and even a book swap. Like any camping trip, I'll probably need two days to recover and return to normal life. Not that life is entirely normal all the time.

posted by scott with 1 Comments

Some Things Just Say "Hack Me"

Everyday I pull into work I see this sign. The sign is of the type you typically see over an interstate highway, but this one sits at the end of a road, behind a government office building that leases space to private companies. I’ve often wondered why the sign was here - at the end of a road with nowhere to go but a parking lot. I’ve never seen a message appear on the sign. I don’t know who controls it. I’ve concluded someone in the government needed to spend some end of the year money in order to pad next year’s budget.

The other day as I was leaving, the sign spoke to me in a clear voice.

“Hack me”, the sign said.

“Huh?” I replied.

“Make me display something funny. I want to make people laugh”, the sign said in a firm but pleasant tone. “Hack me”, it repeated.

It took me a moment to gather my thoughts. I’ve amused co-workers with printer tricks, but this was a tall order. About 35 feet tall.

“You’re nuts”, I replied to the sign. “Most of the people around here are government bureaucrats – they have no sense of humor. I could get into big trouble”.

The sign spoke in a soothing, almost hypnotic voice. “You know you want to do it. You want to find out how to light me up. It’s been a long time for me…”. The voice faded, then returned in the kind of soft, neutral voice that only a talking sign could have. “Hack me in the old-school sense of the word, you know you want to do it”.

I paused to think again and began to feel uneasy. What if someone saw me talking to this sign? Not everything in Columbia, Maryland is as it appears. Why, just around the corner behind a second tree line is a large, unnamed brick building with few windows, two layers of barbed wire fence, and cameras every 200 feet. The NSA moved in, some say, but no one really knows. Someone could be watching.

I moved to my car and tried to ease the sign’s voice out of my head with talk radio. As I pulled out of the parking lot and headed towards the highway, I began to feel I was driving suspiciously slow. I decided I needed to blend in. On the entrance ramp, I slammed the accelerator to the floor and veered hard to the far left lane, all the while gesturing rudely at the faceless cars around me. I felt more inconspicuous with this behavior, which is typical among the breed of commuters in the Baltimore / Washington DC corridor.

My thoughts returned to the sign on the drive home. If the opportunity presents itself, I thought, I should at least have some idea of the message I’d put up. Typically, these signs display something obvious and completely unhelpful. Like when you can see nothing but the brake lights of stopped cars in the distance, these signs will display “CAUTION : CONGESTION NEXT 2 MILES”.

A message like “CAUTION : TREES AHEAD” would be exactly the type of message people would expect to see on a highway sign in front of a forest on a dead end road. It might be so obvious and so un-helpful (in other words, so sign-like), that nobody would ever notice. Nobody except me, of course, and the lonely sign. Not that I'm ever going to touch the sign. Never. Ever.

If you had a giant sign outside of your office, what would you make it say?

posted by scott with 11 Comments

SQL Server Reporting Services and the Validate Path Module

FINAL UPDATE:

This problem is now addressed in the following knowledge base article:

You may receive error messages from Reporting Services after you install the ASP.NET ValidatePath Module.

--

If you’ve installed the Validate Path Module because of the vulnerability in ASP.NET on a machine with SQL Server Reporting Services, then you’ve got troubles. Here is the exception I'm seeing:

Request for the permission of type System.Web.AspNetHostingPermission, System,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 failed. 

I dumped the PublicKeyBlob of the new assembly with the Caspol.exe utility and granted the module Full Trust (as the other GAC'ed assemblies signed by Microsoft have been given). Place the following into both the rssrvpolicy.config and rsmgrpolicy.config files. I placed the entry just underneath the Microsoft_Strong_Name CodeGroup.


     

I hope this gets everyone up and running again. If I see any official configuration information from MS, I'll update this post to pass it along

UPDATE Oct 11: No official word yet. If you are getting the following exception after updating both policy files, than restart the web server (IISRESET from the command line will work). Thanks to Adam Creeger for the tip.

Assembly microsoft.web.validatepathmodule.dll security 
permission grant set is incompatible between appdomains.
posted by scott with 10 Comments

Questions To Ponder

Some of these questions keep me thinking during moments of idle processing….

Q: What happens when we use partial page caching and VaryByControl in ASP.NET?

A: I don’t know.
The documentation says “set the VaryByControls parameter to the ID property value of the ASP.NET server control in the user control that you want to vary the user control output by”. OK … but what exactly does the runtime do with the server control you point to? Does it examine a specific property on the control? Does it examine every property on the control? What does it examine, exactly, to determine if this version is different than the cached version?

Q: Why, when I need just 10 minutes of complete silence to finish an idea, do I never get 10 minutes of silence?

A: I don’t know.
At 2 AM in the morning (typically a quiet time), I am finally on the verge of a mental breakthrough and suddenly the sound of squealing tires outside breaks the silence. The sound wouldn’t be all that distracting except the squeal turns into the noise of a drunken teenager carrening his car through the well manicured shrubbery of my neighbor's front lawn. The next noise is the crunchy thump of car meeting ditch. Then come the fire engine sirens, the state police sirens, and the ambulance sirens. Everyone walks away from the accident without physical injury, but I’ve lost my train of thought.

Q: Why do my Outlook 2003 menus no longer drop down when I hit a shortcut key?

A: I don’t know.
I used to hit Alt+E and the Edit menu would drop down. Then I could hit C, for example, and the Copy command would execute. Now I hit Alt+E and the Edit menu just highlights. Hitting an accelerator key like C then doesn’t do anything at all. Aggravating!

Q: What does it take to get some link love from Rory Blyth?

A: I don’t know.
However, Rory is having a contest, and you can win a nice prize.
I'm entering Rory's stupid contest, and I'm lowering my chances of winning by telling you about it, too.

Q: Why does Virtual PC give misleading numbers in the task manager?

A: I don’t know.
With the VPC beta you could launch VPC and look in task manager and see a reasonable approximation of how much RAM the virtual machines were using. Since the release I look at Virtual PC while I am running a machine with 512MB of RAM and VirtualPC.exe is only using 17MB of RAM. Weird.

Q: What is the deal with my PocketPC and Secure Digital Memory Cards?

A: I have no idea.
Sometimes the contents of my SD cards simply disappear - all the files are gone. Sometimes the cards fill up with directories named ‘.’. I’ve tried two different cards in two different Pocket PCs – it happens on every combination. I use the cards to carry MP3 files around – nothing important – and I used to play the MP3s with Windows Media player. I thought it might be WMP wiping out the storage cards – so I tried Pocket Music, but the same thing happens. I’ve tried utilities to reformat the cards. I’ve tried utilities to scan for defects – none. I don’t know anyone else with this problem, so I’m beginning to wonder –

Q: Do I attract more cosmic rays than the average human?

A: I don't know.

[Currently listening to: NOTHING! And it's nice and quiet that way (0:10)]

posted by scott with 7 Comments

Q&A About the Community Starter Kit

Here are some questions I received after last night’s presentation on the Community Starter Kit.

Q: Where does the WYSIWYG editor come from?

A: The WYSIWYG editor is an HTML component (HTC). In the CSK, you can find a file named HtmlTextBox.htc that implements the HTML editor component. The HTC file uses a mixture of HTML, JavaScript, styles, and object tags to implement the editor.

It looks as if Paul Abraham has broken out the HtmlTextBox.htc file from the CSK and repackaged the component into a standalone assembly. I haven’t tried this but it looks interesting. Another editor I've seen in applications is the control from from FreeTextBox.com. There is also an assortment of editors and other controls in the ASP.NET content management control gallery.

Q: Can we port the CSK to Oracle?

A: Backend portability was not in the design goals for the CSK. It is possible, but requires some work. First, there is a total of about 200 stored procedures and user defined functions (UDFs) in the SQL Server database you’ll need to port over to Oracle. Each class representing a content type in the domain model architecture of the CSK will also need to be modified – as they are using the SQL Server specific SQL provider classes of ADO.NET. The good news is, once you get all that done – it’s all downhill!

Q: Why do the ASCX files have no code-behind?

A: Unfortunately, I tried to cover too much in this presentation and didn’t get to address this issue properly. Usually when we build ASCX files, we drop controls in the ASCX and in the code behind the ASCX we tell the controls what to display. The CSK works a little differently. We still put controls into the ASCX but the controls themselves are highly customized and already know what they need to display.

The ASCX files then strictly serve as skins. They are simply there to layout where the controls will appear. There is no logic associated with the ASCX file – no code. Each control is customized to do a specific duty. For example, when you plop a community:Author control on the page, the Author control knows it has to display the author’s name for a piece of content. All of the logic is inside this web control - the skin file determines where the control will display.

Q: Are there any sites supporting fixes and customizations of the CSK?

A:  Three I know of, there could be more…

Stephen Redd’s Site (full of CSK Articles, Mods, and Fixes)
Dave Rank’s Personal Web Site
Matthew Roche’s CSK Resources

Q: What is the ASP.NET vulnerability you were rambling about?

A: This is not related to the CSK – it’s a bug in the ASP.NET runtime and is very serious. You need to view the following Microsoft documents and implement the suggested fix as soon as possible until a patch can be provided.

What You Should Know About a Reported Vulnerability in Microsoft ASP.NET
Programmatically check for canonicalization issues with ASP.NET

 

posted by scott with 4 Comments

WebRequest and Binary Data

Someone sent me an email today describing a problem when downloading a binary file with the WebRequest class. There are plenty of articles (including some of mine) with screen scraping code like the following:

WebRequest request = WebRequest.Create(someUrl);        
using(WebResponse response = request.GetResponse())
{
   using(StreamReader reader = new StreamReader(response.GetResponseStream()))
   {
      string result = reader.ReadToEnd();
   }         
}

Unfortunately, StreamReader is only good for reading text. When it comes to binary data the result has a good chance of being incomplete. The approach for binary data is to stick to the basic Stream type and read raw bytes.

byte[] result;
byte[] buffer = new byte[4096];
 
WebRequest wr = WebRequest.Create(someUrl);
 
using(WebResponse response = wr.GetResponse())
{
   using(Stream responseStream = response.GetResponseStream())
   {
      using(MemoryStream memoryStream = new MemoryStream())
      {
         int count = 0;
         do
         {
            count = responseStream.Read(buffer, 0, buffer.Length);
            memoryStream.Write(buffer, 0, count);
 
         } while(count != 0);
 
         result = memoryStream.ToArray();
 
      }
   }
}

P.S. IDisposable lurks everywhere!. It’s a shame some classes use an explicit interface implementation and hide the Dispose method from Intellisense.

P.P.S. Commercials are the best things going on Monday Night Football these days. Except the commercials for other ABC shows. I don't know why I turn on television.

posted by scott with 14 Comments

Look For Me In January

I got word this week from Tony Elias, development editor for MSDN Magazine, that I'll be in the January issue with my article “Living The Static Life”. The article will cover all the deep, dark secrets you ever wanted to know about shared and static members of a class. Visual Basic.NET and C# code included!

posted by scott with 3 Comments

And The Winner Is … Xandros

I’ve been looking for a Linux distro to run under Virtual PC so I can get the latest build of mono running again. Previous attempts at installing the most recent Linux distros all ended with kernel panics - apparently, there is a problem on VPCs with P4 Prescott processors.

After reading Jerry Pournelle’s column (Chaos Manor) in last month’s Dr. Dobb’s Journal, I decided to give Xandros a try. A hard-core Linux distribution this is not. Any unix software which creates a “My Documents” directory is sure to make a true Linux fan sputter obscenities. I’m not a hard core Linux fan, and I think Xandros is nice and clean. What would really irritate me about RedHat and the others is all of the garbage they install by default. Do I really need 4 different web browsers on my desktop?

I now have mono up and running again. It took some work. Xandros is supposed to be for the relative compute newbie. As such, the free version doesn’t come with a cvs client or any other development tools (except a C++ compiler). However, I think starting clean and adding what I needed actually enabled everything to work for me on the first try, unlike previous attempts at getting mono built from source, which only resulted in google-ing for obscure error messages and coming up empty.

I had to install the following to get mono running on Xandros:

pkgconfig-0.8.0
glib-2.0.6
gc6.alpha5

autoconf-2.59
automake-1.9
bison-1.875
icu (note: change CFLAGS from -O2 to -O3 in icudefs.mk to work around a GCC optimization bug, argh).
libtool-1.5.10
mono-1.0.2
mcs-1.0.2

Each piece of software is installed using the typical ./configure, make, make install process. I had to add /usr/local/lib to ld.so.conf (then run ldconfig to reconfigure the bindings), and wow, it finally all works!

posted by scott with 0 Comments