Today I have stepped up to the position of “Director of Operations” in our local Austin .Net User Group. I look forward to being more involved with the development community and contributing.
Check out the ASP.NET Developer center for some changes from ASP.NET Beta 1 to Beta 2. I welcome some of these changes because I was in the croud that logged bugs against Beta 1, and these actions resolve the bugs. The special directory names are changing. Here are the changes:
/Bin (formerly Application_Assemblies) |
stays the same |
/Bin |
/Code (formerly Application_Code) |
Becomes |
/app_code |
/Resources (formerly Application_GlobalResources) |
Becomes |
/app_globalresources |
/LocalResources (formerly Application_LocalResources) |
Becomes |
/app_localresources |
/WebReferences (formerly Application_WebReferences) |
becomes |
/app_webreferences |
/Data (formerly Application_Data) |
becomes |
/app_data |
/Browsers (formerly Application_Browsers) |
becomes |
/app_browsers |
/Themes (formerly Application_Themes) |
becomes |
/app_themes |
Generated event handlers will be marked as protected instead of private going forward.
The .aspx will no longer be a partial class with the code file and a system file. Instead, the .aspx will inherit from the code file, which will be a partial class with a system file. This solves the problem of not being able to reference UserControl types at design time.
Another great thing, though, is that VWD2005 supports intellisense in the .aspx, so for whipping up code samples for newsgroups or my blog, I can just use a single file. Yeah, I know, I’ve grown lazy and depend on intellisense, but when is the last time you actually got up to change the channel on your TV??? Addicted to the remote control???
Last night, Christoph gave a great talk and demo on Web services and WSE 2.0. I haven’t used WSE yet, so, of course, it seemed like a mystery, but again Microsoft did a great job of making it work with just a few lines of code. WSE deal with the security aspects of web services. Both the client and server have to be using it, though. I found out that if I’m interopping with an older technology using the Soap Toolkit, then I’m stuck with Web Services 1.0 and my own security scheme.
There are plenty of articles out that explaining how to validate Xml, but they all seem to use namespaces or have other factors in them. I didn’t find one that used plain Xml with no namespace declaration, so I whipped up a little example. I included the Xml and Xsd inline and load it using a StringReader, but for your purposes, they would probably be in physical files.
string xsd;
string xml;
xsd = @”<xs:schema xmlns:xs=””http://www.w3.org/2001/XMLSchema””>
<xs:element name=””address””>
<xs:complexType>
<xs:sequence>
<xs:element name=””name”” type=””xs:string””/>
<xs:element name=””street”” type=””xs:string””/>
<xs:element name=””city”” type=””xs:string””/>
<xs:element name=””country”” type=””xs:string””/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>”;
xml = @”<?xml version=””1.0″”?>
<address>
<name>John Smith</name>
<street>109 Abbey Close</street>
<city>Hayes</city>
<country> UK</country>
</address>”;
XmlValidatingReader vr = null;
vr = new XmlValidatingReader(new XmlTextReader(new StringReader(xml)));
vr.Schemas.Add(null, new XmlTextReader(new StringReader(xsd)));
vr.ValidationType = ValidationType.Schema;
vr.ValidationEventHandler += new ValidationEventHandler(vr_ValidationEventHandler);
// Validate XML data
try{
while(vr.Read());
}catch{
Console.WriteLine(“Xml Document is not well-formed.”);
}finally{
vr.Close();
}
There are a lot of people having issues when they have to change the location of the web service they are calling. Some resort to recompiling the proxy class, but that isn’t necessary. The proxy class that is generated by VS hard-codes the URL of the web service in the class, but with a little foresight, you can avoid problems when the location of the web service changes. First, let’s create a configuration item to control the URL where the web service resides:
<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
<appSettings>
<add key=”webServiceUrl” value=”http://localhost/service.asmx” />
</appSettings>
</configuration>
Now, we just add 1 line to the code that calls this web service:
myWebService.Batch service = new myWebService.Batch();
service.Url = ConfigurationSettings.AppSettings[“webServiceUrl”];
Debug.WriteLine(service.Url);
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
service.MyWebServiceMethod(textBox1.Text);
Debug.WriteLine(“Called web service”);
By setting the “Url” property, we can change where the system goes to consume the web service. Now, you can deploy the web service to any server, and if you change your app.config file, your client code won’t miss a beat.
Yesterday afternoon, my web application broke. I have a page that takes a user data file and saves it to the server. I have a web service that takes the contents of a file and does the same thing. A process consumes these files on our development server. I am developing part of it on my machine and dropping the file to the DEV machine for consumption, so I’m creating files on a UNC path. Mysteriously I started getting UnauthorizedAccessException, but my code had been working. I didn’t change anything. I double-checked all the important stuff (identity impersonation, security, etc), and everything was in order. I did the normal research. . . Google groups. For all of you Googlers out there having problems with this exception, I have a solution. Reboot! I checked everything I could think of, and I remembered the rule of thumb that I always tell everyone else: “When in doubt, reboot.” Since I’ve been using Win XP and now 2003 Server as my dev OS, I haven’t had to do much rebooting. My home computer (XP Pro) hasn’t been rebooted in at least two months, and it gets a lot of abuse as well as having umpteen external devices connected to it.
I’m using Windows Server 2003, and it is very stable, and even with the abuse I put it through, this was the first time I’d rebooted this week. It’s a laptop, so I hibernate it. I rarely reboot, but remember that when there is no rational explanation for a problem. . . reboot.
For people starting out with ASP.NET, the appSettings node in the web.config file will be all that is necessary for storing configuration items, but when you start creating your own config section handlers and strongly-typing your configuration items, you may run into a small snag that may cost you 1/2 a day to track down.
Configuration section names (since they are xml) are case sensitive. Xml is case sensitive.
I have a section:
<configSections>
<section name=”SiteMap” type=”WebTestHarness.SiteMapConfig, WebTestHarness” />
</configSections>
but if I call:
ConfigurationSettings.GetConfig(“siteMap”);
I get mysterious errors elsewhere in my code. My config section didn’t get loaded. It turns out that the section “siteMap” wasn’t found. “SiteMap” is the correct name. Of course, I expected the .GetConfig() method to throw an exception if the section wasn’t found, but it doesn’t. It just returns nothing and lets my code keep going.
Now, armed with this knowledge, I will just check the return value of the method to determine if the GetConfig was successful.
If for some reason you need to capture page output either to log it, analyze it or do a global string replace, then you will need to intercept the rendered Html before it makes it to the wire on the way to the client. Here is a code snippet that will do just that.
protected override void Render(HtmlTextWriter writer)
{
StringBuilder sb = new StringBuilder();
HtmlTextWriter htw = new HtmlTextWriter(new StringWriter(sb));
base.Render(htw);
writer.Write(sb.ToString());
Trace.Warn(sb.ToString());
}
The StringBuilder will get the content, and you can do with it what you please. Then just make sure to call writer.Write( ) to render the final content to the Response stream.
A CheckBoxList can be useful, but have you ever tried to disable a single checkbox in the list? There are a lot of people who want to do just that. Here are some ways to do it.
http://www.mredkj.com/vbnet/CheckBoxListItemDisable.html
http://www.codeproject.com/aspnet/disableListItems.asp
There are a few things to keep in mind when you create controls on the fly and add them to your page. Simply put, you want to add them to the page hierarchy as soon as possible. Before they are added to the page, they have not initialized themselves. When a dynamic control is added to another control, the new control plays catch-up to get to the stage that the parent control is in. For instance, if in your Page_Load, you add a textbox, it will play catch-up and go through its Init and Load phases. This is important beceause it will start tracking its viewstate. Values added before it is tracking viewstate won’t make it to viewstate and will be lost on PostBack. Here is an example that won’t work:
TextBox txt = new TextBox();
if(!IsPostBack)
{
txt.Text = “test value”;
}
this.Form1.Controls.Add(txt);
This example shows setting a text property BEFORE this control is added to the page (and before it is tracking viewstate). Next, we’ll show the right way to do it:
TextBox txt =
new TextBox();
this.Form1.Controls.Add(txt);
if(!IsPostBack)
{
txt.Text = “test value”;
}
Note here that we add the control to the page BEFORE we set a property. This enables our dynamic control to participate in viewstate as well as the rest of the page lifecycle.
To clarify, if we add a dynamic control during the Page’s PreRender, when we do the Controls.Add( ) function, the new control will go through Init, Load and PreRender immediately to catch up with its parent (the Page).