In recent years the development story for Internet Explorer wasn't particularly appealing. If you wanted to fix CSS and JavaScript errors, IE was definitely not the tool you wanted to use. Also, seeing what was going over the wire wasn't possible with IE, and as a result developers flocked to FireFox and other browsers offering (plugins) to help with these issues. You don't have to be a genius to understand that in the long run this wasn't helping IE in terms of market share. And with the renewed focus on webbased (HTML5) apps, Microsoft has stepped up and produced built in developer tools, also known as the F12 developer tools. So, what's in there and what can you do with it? What's taking so long?As with IE8, there are inspector tools for HTML, CSS, and script. Since I am by no means an HTML/CSS guy, I'm not the best judge when it comes to these tools, but for what I need from those I've been pretty satisfied. For me, the new profiler and network tools are much more interesting, because they respectively hook into the browser rendering engine and what's going over the wire with HTTP. If you've been using tools such as Fiddler or HttpWatch, the latter of the two should be more or less familiar. As you can see in the image below, it shows all the HTTP requests going out to the server, when in the timeline these requests were going out, and how long that took. If you've never seen something like this, you can see that this provides great insight into what goes down under the covers.  If you need more details about the timing information, you can select one of the items, and see more. As you can see below, that information doesn't only include HTTP information, but also information about the time it took to render and JavaScript to fire. If there's a page that is slow to appear in the browser screen, this will give you great insight into where your time is going.  Is this functionality better than commercial tools such as HttpWatch? Not at this time, but I have a feeling Microsoft isn't done yet. Tools like that are specialized, and Microsoft is playing catchup. One annoying thing I found is that if I have multiple requests bouncing back and forth, filling in a form, etc. IE9 tools will only show me the last interaction. It could be I'm missing something, but I haven't been able to figure out how to see the whole list of requests since I started capturing, and I'm too lazy to figure it out. That means I find myself going back to HttpWatch for that (at the moment). That said, the tooling is good, so if you don't want to spend the extra dime for other tooling, this will do in most cases. Except of course that this only works in IE9, whereas some of the tools out there work in multiple browsers. But wait... there's more. What I'm I getting?An interesting question is always: what HTML will a certain browser actually get. This is where the F12 tools have another nice new feature. You can change the user agent string the server is receiving, and as a result inspect what happens on the HTML, CSS, script side when other browsers come in. Obviously this doesn't make IE9 behave itself as one of the other browsers, but it can provide nice insights nonetheless, especially to tweak what robots are seeing.
 How will it look?The last thing that I fond really useful is the ability to change the browser so you can check the user experience for users with different settings. As you can see from the image below, you can disable css, script, and the pop-up blocker. In the environment I'm working in now, there's often the need to see whether everything still works if JavaScript is disabled, and there this is a great tool. It definitely beats going into the browser settings and changing these settings every time you have to test.
 Last but not least, you can easily resize the browser screen to fit a certain size. I always used Windows Sizer for this, but having this built in is better, because I rarely use it for anything but webdevelopment.  What's more?
There's a whole bunch of stuff I haven't gone into here, so I advise you to play around with the F12 tools for a while. I'm also betting we'll see a lot more where this came from in the not too distant future. Microsoft is investing heavily in HTML5, and is actually trying to use "the best HTML5 support" as a unique selling point for Windows.
I sometimes use the Visual Studio Class Diagram when I'm designing a system. Because I like to test my assumptions in such a situation I want to be able to quickly create classes that just work. Unfortunately, when you add a property in a class, Visual Studio generates code like this: public string SomeProperty
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}
In most cases what I need is: public string SomeProperty { get; set; }
Fortunately, the PowerToys for the Class Designer and Distributed System Designer solve this problem. After installing these (and turning it on in the Add-In Manager), the right click menu is enhanced with a lot of new options. One of the is Add->Auto-Imlplemented Property, as shown below.
Earlier I blogged about finding performance issues in an ASP.NET app "in the large" (see here). I'd like to reiterate that doing this for a web app is critical, because it not only shows you where the bottlenecks are, but also how these affect the entire application. I said I'd follow up on profiling, so here it is...
Once you know what the bottlenecks or "hot spots" are, you can dive into figuring out what the problem is with these pages. This is where profiling comes in. Profiling lets you know what is happening inside your code. It shows you how long a method call is taking and how often a call is made. Both of these are interesting, because performance bottlenecks can be caused by calls taking long, but also by too many calls to a method. Now, I won't get into the details of how to profile with Visual Studio 2010 (you can read Beginners Guide to Performance Profiling for that), but when you use this tooling, you should focus on one page at a time. The profiler will throw a heap of information at you, so dealing with one page is hard enough. Once you have this information you have to determine what's really going on. Is this somehting you can fix by changing a few lines of code, or is there a more structural problem you need to solve? Pages that under no load take 10 seconds or more likely have a structural problem, so you need to check if there is a lot of code being executed that is just waste. Also, be sure to focus on big fish first. You can worry about micro-optimizations (such as a different string compare mechanism) later. That said, you should try to make such optimizations part of your coding guidelines, rather than looking at that afterwards. Micro-optimizations are only really interesting for very high performance apps. A 10th of a second loss here and there isn't going to make a lot of difference apart from maybe needing to scale-out a little earlier.
It is typically a good idea to separate general authorizations of a user from application specific authorizations. This is why we invented Application Roles (Settings Administrator), which are separate from Organizational Roles (System Administrator).When using Application Roles, we can map these roles to Organizational Roles. In organizations using Active Directory, Organizational Roles are typically stored in AD. Application Roles can then be stored using Authorization Manager (AzMan) in XML or AD in Application Mode (separate from the organization AD).
Over the years I've built quite a few applications that use the above model, and it works well if you authorize with roles. But these days I do most of my work using things like Claims Based Authorization, so the question is "Does this translate to teh CBA world? And if so, how?". The answer is that yes, it does translate (very well actually), at least in Windows Identity Foundation.
In the CBA world an application receives a token with claims about the user. Like with roles, this should typically be claims not specific to the application, unless the only source for the claim information lies within (or is only accessible to) the STS. This serves two purposes:
- The token is generally usable across applications, so the STS can deal with this more easily.
- Tokens are not stuffed with a lot of claims.
The latter is actually more important than you might think. Adding more claims means a bigger token, and there comes a point where the token is so large that for instance ASP.NET rejects the request, because it is bigger than the accepted request size (which you should only increase if really necessary).
Now, one of the great things about CBA is that it enables me to create business logic which checks the authorization based on meaningful values, rather than a role. On top of that, I wouldn't want to have a hybrid security system for the claims stuff and the application specific stuff. Fortunately, In Windows Identity Foundation I can add claims to a claims identity, and these claims then behave the same as the claims acquired from the STS token. The only difference is that the issuer is set to LOCAL AUTHORITY, rather than the STS, which means these claims are really only usable locally in my app (or service). The code to add a local claim is easy: IClaimsPrincipal claimsPrincipal = Page.User as IClaimsPrincipal;
IClaimsIdentity claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;
claimsIdentity.Claims.Add(new Claim("http://MyApp/SomeAppClaim", "SomeValue"));
You can execute code like this when a session starts, and add all application specific claims for the user (identified by an STS claim) to the claims identity. The local claims then get the same lifetime as the claims originally from the token, so you only have to add them once. This way adding application specific claims is still separated from the functional code. Which was the benefit to start with.
Although the above code will definitly work, there is another option when using WCF, known as Claims Transformation. With Claims Transformation you can define policies that define ClaimSets to add to a user's token. This model is much more flexible, as explained in the MSDN article Service Station: Authorization in WCF-Based Services (jumps straight to the Claims Tranformation section). That article is from the pre-WIF era, but you can do similar stuff with teh ClaimsAuthorizationManager in Microsoft.IdentityModel.
Performance issues can creep up in all sorts of places. Finding them is all about knowing where to look. This also depends on how you look, which can be at the application as a whole ("in the large") or at individual functions ("in the small"). The latter is known as profiling. Because (ASP.NET) web applications are all about large numbers (of users), looking at the application as a whole is a good place start. This is where load testing (a.k.a. stress testing) comes in. Load tests will show you which pages are performing poorly, which is the first step in determining where to take a closer look. Load Testing 101: ASP.NET Web Applications is a great starting point to get yourself up to speed with the mechanics of a good load test, even though its from 2006.
One thing in the article that I think is absolutely critical is about creating a single user base line. This will show you which pages are doing well, when run on their own vs. pages that are doing not. The results of that test already give you an indication of where to look. In fact, a full load test may actually skew the results, because fast pages can be held up by slow pages if the request queue fills up. Fast pages can be identified under load from the difference between the best, average, and wordt results. For fast pages these show huge differences (from few tenths of a second to tens of seconds), whereas slow pages have numbers which are bad across the board.
If you're looking for tools to do load tests, checkout the Web Capacity Analysis Tool (WCAT) provided by Microsoft. The downloads can be found here:
An interesting tool you can use with WCAT is the WCAT Fiddler Extension for Web Server Performance Tests. It helps you to record a path through your app with Fiddler, and then use that path in a WCAT load test.
Note: I will cover profiling ("in the small" testing) in a different post.
Op het SDN Event van 13 december heb ik twee presentaties gegeven. Hieronder kun je de aantekeningen downloaden die ik gemaakt heb op de tablet (voor wie er niet bij was: ik heb in plaats van slides mijn sessie gedaan met behulp van tekenen in OneNote).
De demo's bij ASP.NET Aanpassen volgen op korte termijn (vermoedelijk komend weekend... leuk speelgoed voor de kerst).
A recurring theme in web programming is calling a function periodically and/or at a specific date and time. This has two aspects:
- Calling a function on a scheduled basis
- Making sure time-outs don't interfere
Calling a function on a scheduled basis To be able to call a function on your web app, you first need an endpoint (a URL) that you can call to kick the function off. In ASP.NET you can do this in several ways:
- Create a page that calls the function.
- Create a handler (ASHX) that calls the function (more efficient than a page).
- Create a WCF service that allows calls with HTTP GET, as discussed in this blog post by Sasi Suryadevara.
With your endpoint in place, you can use the Windows Task Scheduler to invoke the function at any given time and at intervals as low as one minute. With the Windows Task Scheduler you have several options again:
- Create a VB Script that calls the URL, as discussed in this blog post by Steve Schofield.
- Create a PowerShell script that calls the URL (same as option 1, but more modern).
- Have the Windows Task Scheduler open Internet Explorer and open the specified URL (e.g. C:\PROGRA~1\INTERN~1\iexplore.exe -extoff http://www.google.com, which starts IE without extensions). If you do this, you also need to specify that the Task Scheduler closes IE after 1 minute, which you can do in the Settings tab of the task (Windows 2003), or in the Trigger configuration (Windows 2008), as shown below. NOTE: I've found that IE sometimes doesn't close, even if you tell Windows to close it. Eventually this will cripple your scheduled task.
 Task Settings in Windows 2003
 Trigger configuration in Windows 2008
Note: In Windows 2008 the dropdowns governing duration and interval show 30 minutes as lowest value. You can in fact change this to 1 minute by editing the text.
Making sure time-outs don't interfere A web based call is bound to time-out after a few minutes. If you task takes longer than that, this may abort the call depending on how you programmed it, and what webserver settings are used with regards to disconnected clients. To ensure a time-out does not interfere, you can spawn a new thread and have it call the function. That way the thread handling the request can return a response to the client, and the function is carried out regardless. One issue that may arise there is that the function itself hangs or takes too long. You may want to add logic to ensure that it's aborted after a certain time, and add logging to notify you of this, and possibly also ensure that the function can only be run by one caller at a time.
Sometimes we come across integration scenario's that look straighforward, but where the devil is in the details. We needed to integrate our asp.net/silverlight application in an existing ASP "classic" site (yes, the still exist). The catch was that we needed to call the ASP "classic" site in a server to server call to get some information, but we needed to do this under the context of the current user. You may be wondering why we didn't go through a shared database or someting, but the problem is that there is little knowledge left of the old app, so changing the existing app was a no go.
So, in order to impersonate the user, you need your server-sided request look like that user. This means forwarding the cookies the user sends, and sending back the cookies the server sends to the user. Below is code that demonstrates that. HttpWebRequest webRequestToServer = (HttpWebRequest)HttpWebRequest.Create("http://somedomain/somepage.asp");
webRequestToServer.CookieContainer = new CookieContainer();
foreach (String cookieKey in Request.Cookies)
{
HttpCookie cookie = Request.Cookies[cookieKey];
Cookie serverCookie = new Cookie(cookie.Name, cookie.Value, "/", "somedomain");
webRequestToServer.CookieContainer.Add(serverCookie);
}
HttpWebResponse webResponseFromServer = (HttpWebResponse)webRequestToServer.GetResponse();
foreach (Cookie serverCookie in webResponseFromServer.Cookies)
{
HttpCookie clientCookie = Response.Cookies[serverCookie.Name];
if (clientCookie == null)
{
clientCookie = new HttpCookie(serverCookie.Name);
}
clientCookie.Value = serverCookie.Value;
clientCookie.Expires = serverCookie.Expires;
Response.Cookies.Add(clientCookie);
}
webResponseFromServer.Close();
This code works fine in a test environment, but there is a catch... in some cases the domain of the server is not set in the cookie you get on the server side. The problem with that is that when you set the domain, it doesn't correspond to what the server expects. You can see this if you write out the cookies you send/receive (both on the browser connection and te server-server connection) to a log or something (including the domain. It took a while to figure out, but replacing "somedomain" with Request.ServerVariables["LOCAL_ADDR"] did the trick.
Two months ago I spoke at WDI 2010 in Warsaw, Poland on ASP.NET Web Forms vs. ASP.NET MVC. I should have posted the slides for that session soon after, but just didn't get around to it because of all the work thrown at me. Here they are... finally. Slides (668.34 KB)
Thanks to the great folks organizing the conference. They took great care of me and managed to get a good crowd together. Even though it was a pretty large audience, the level of interaction was very good.
Soms verandert de realiteit zo snel dat iets wat in een magazine bij mensen op de deurmat valt alweer verkeerde informatie staat (tja, dat heb je als op de PDC weer van alles aangekondigd wordt). In mijn artikel voor SDN Magazine 103 - ASP.NET onder de motorkap: ASP.NET op bezoek bij de browser staat een link naar de ASP.NET AJAX Library die inmiddels al verouderd is en een foutmelding oplevert. Je kunt nu naar http://ajax.codeplex.com/. Met dank aan Leo Broos die me liet weten dat de oude link niet meer werkt.
My company regularly works on public facing websites, and as such it is imperative we test the sites we create with most common browsers. Naturally that means at least Internet Explorer, FireFox, Safari, and Opera. With the last three we just download and install om some test (virtual) machine. With IE however this is somewhat more complicated (although not impossible to run different versions of IE side by side. However, Microsoft provides a set of Virtual PC images known as the Internet Explorer Application Compatibility VPC Image. These images enable you to test different versions of IE on different versions of Windows. These images have a limited lifetime (between 1-4 months), so you'll have to download a new set on a regular basis, but other than that this is really handy. The following configurations are available:
- Windows XP SP3 with IE6
- Windows XP SP3 with IE7
- Windows XP SP3 with IE8
- Windows Vista with IE7
- Windows Vista with IE8
Unfortunately these configurations are all en-US, so if you want to test with say a Dutch version of Windows, you'll have to create your own images (which is what my company has done, even for en-US).
Today http://orchard.codeplex.com/ went live. Orchard is an open source Content Management System that the folks from Redmond are working on together with the ASP.NET community, and which I've been following with much interest. Orchard is based on ASP.NET MVC, which means I'd favor it over something like Umbraco when it is mature enough. Why? Because this should mean that it blends easier with your regular development efforts, rather than having to deal with an entirely different templating technology. Umbraco for instance uses XSLT, and even though I wrote a book a about XSLT and my company is well versed in XSLT because we do a lot of BizTalk, it is troublesome for plain ASP.NET developers.
Keep in mind that Orchard is relatively new and a lot of scenario's are still not supported. But at the pace the team is going, you'll soon see more advanced stuff being possible. You can make yourself heard about what you'd like to see through CodePlex or through one of the sessions at TechEd or PDC this month.
We have an ASP.NET application that we normally run under Forms Authentication using the ASP.NET Membership API. For a particular client we changed this to using Windows Authentication instead. On the production environment, we were running into the following exception:
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)
We checked all the connection strings the app uses... all good. Finally, we figured out what was wrong. We had removed the Membership section from web.config so it was going back to the default in machine.config. That setting uses the LocalSqlServer connection string, which we don't use. However, in the default machine.config, this points to the App_Data folder using SQL Server Express. In most environments, this wouldn't be an issue immediately, because SQL Server Express would just create the aspnet database and use that. However, in a hardened environment SQL Server Express is either not there (our case) or has no rights to create the App_Data folder and/or place create a new database. ASP.NET doesn't know this... it just can't access the SQL Server instance it is looking for, hence the above exception.
Iedereen die mijn sessie bezocht heeft tijdens de SDE van 30 maart bedankt voor het luisteren. Hieronder vind je links naar de slides en voorbeeldcode.
Geavanceerde UI Technieken voor SharePoint Slides (126.2 KB) | Samples (447.66 KB)
De voorbeeldcode bevat ook een installer om de WebParts uit te rollen. Je moet wel even uploadskinfeature.bat aanpassen om naar de juiste server te wijzen.
Recently I encountered an exception related to System.Security.Permissions.FileIOPermission while trying to send email from ASP.NET (dasBlog actually). This has nothing to do with rights set on folders! It is a trust (code access permission) issue, and it will happen if your application is running under Medium Trust. Elevating the trust level will definitly help. From what I've read, defaulting to the system defined SMTP settings (i.e. removing any SMTP settings form web.config) will also work, but I have not tried this yet.
Thank you for all who attended my sessions in San Francisco. Below are the slides and samples for my sessions.
VTH4 - Understanding Transactions in WCF Slides (561.73 KB) | Samples (540.1 KB)
VTH16 - Supporting POX/REST with WCF Slides (369.58 KB) | Samples (302.82 KB)
VTH25 - Simplify WebPart (and Control) Development with WebPart Skinning Slides (359.85 KB) | Samples (447.66 KB)
The VTH25 samples include the full installer. However, be sure to change the uploadskinfeature.bat to point to the correct server. You can read more about the VirtualPathProvider I mentioned in VTH25 session here.
The wonderful folks at VSLive! have invited me again to do three sessions at their San Francisco event from February 23 to February 27, 2009. These are the sessions I'll do (all on Thursday 26):
- Understanding Transactions in WCF
- Supporting POX/REST with WCF
- Simplify WebPart (and Control) Development with WepPart Skinning
The first two are obviously about WCF. The last talk is primarily about SharePoint, but the discussed techniques will work with ASP.NET WebParts and WebControls as well.
I really like VSLive! because they have some great content and top tier speakers. The speakers (myself included of course) are also very accessible, because the event is not as huge as some of the other conferences these days. So if you intend to go to a conference this year, VSLive! is going to be worth your money.
At a session about ASP.NET DynamicData at VSLive in Dallas, one of the attendees asked me about my thoughts of DynamicData becoming a part of ASP.NET MVC. I commented that currently DynamicData is very much based on the current ASP.NET paradigm of pages and controls, whereas ASP.NET MVC is not. ASP.NET MVC presents a new way of thinking to the ASP.NET world and I find it hard to believe that millions of developers will jump on the ASP.NET MVC bandwagon immediately after its release (let's face it, it hasn't even been released yet) and leave their old coding styles behind. You need to learn to think differently first. Also, if ASP.NET MVC becomes the primary ASP.NET paradigm, there is a whole lot of code that is still using ASP.NET the way most of us do at the moment. That said, ASP.NET MVC is very interesting.
Ok, so back to the original question. If you look at Scott Guthrie's post about the ASP.NET MVC Release Candidate, you'll see that there is scaffolding support on based on the model, instead of table based scaffolding using in ASP.NET DynamicData. The model based scaffolding enables you to create different views of the model in no time.This is very cool, because it provides you with way more control over what is happening than in DynamicData. And because it is based on the model, you're not tied to database objects, but rather to business objects. How you persist those is up to you.
I still think ASP.NET DynamicData and ASP.NET MVC are going to live side-by-side for quite a while, and that they will use concepts that were created for one or the other. The main reason for this belief is based on my earlier comment: I think ASP.NET MVC and ASP.NET "Classic" will run side-by-side for a loooooong time. I do feel that ASP.NET MVC ultimately provides us with more flexibility and will at some point become the more dominant paradigm.
At VSLive in Dallas last week I promised to follow up with a post about securing an ASP.NET Dynamic Data application. Your first concern is not exposing all the tables, so although it demo's well, never set ScaffoldAllTables to true. That however, does still not solve how you can provide read-only access to certain users, while providing edit access to others. The most elegant way to do that is at the Data Model level, using a custom security attribute. There's a great sample on how to do that on the Dynamic Data Samples on Codeplex. The specific sample you want is Secure Dynamic Data.
If you don't want to spend the time to understand how security at the Data Model works, you can also just use ASP.NET Roles to secure specific parts of your site. Since securing folders/files that way has been around since ASP.NET 1.x, that should be easy enough :). There is a gotcha though: you cannot secure dynamic folders. In other words, a Dynamic Data path /SomeTable/List.aspx is not securable, because SomeTable is not an actual folder. With three simple steps you can get around this.
Step 1: Create a folder corresponding to a specific role, for example "Readers".
Step 2: Create a web.config in that folder limiting access to the role(s) you want to give access.
Step 3: In globas.asax, route the tables and actions that apply to the specific role to that folder, like this:
routes.Add(new DynamicDataRoute("Readers/{table}/{action}.aspx") { Constraints = new RouteValueDictionary( new { action = "List|Details", table = "EvaluationSubjects|Reports", }), Model = model });
I will be speaking at VSLive! again, this time in Dallas from 8 until 11 December. I'll be doing the following sessions:
- Introduction to ASP.NET Dynamic Data (Tuesday 9 December, 11:15 AM)
- POX/REST Strategies with WCF (Thursday 11 December, 1:45 PM)
- Understanding Transactions in WCF (Thursday 11 December, 4:45 PM)
VSLive! is a very nice and relaxed event with great content. So it's a great opportunity to learn new stuff and new people. If you want to attend the Dallas show and see me speak, you can get a $300 discount by entering the discount code SPVAN. I hope to see you there.
I while ago I created the control shown below. It acts a multi-select ListBox from the API perspective, but works by selecting items and moving them over. Pretty much all elements can be styled, such as the headers, the ListBoxes and the buttons. I'd love to have one with some JavaScript that allows drag-n-drop, but that's too much work for me. Feel free to copy and extend the source code(3.15 KB).
Microsoft heeft ten aanzien van jQuery een opmerkelijke stap gemaakt. In plaats van zelf iets jQuery-achtigs te maken, heeft Microsoft aangekondigd jQuery zelf te gaan ondersteunen en nieuwe onderdelen van ASP.NET AJAX op jQuery te baseren. Dit is zowel door jQuery als door Microsoft bevestigd. Ik ben hier persoonlijk zeer verheugd over en ik hoop dan ook van harte dat Microsoft deze lijn doorzet. Ik heb veel liever dat Microsoft ondersteuning biedt voor (toonaangevende) bibliotheken dan er zelf een (vaak minder goede) kopie van te maken. Overigens is het niet alleen zo dat Visual Studio jQuery technisch gaat ondersteunen, maar ook dat klanten van Microsoft support kunnen krijgen via Microsoft. Ik ben benieuwd of er nog meer gaat volgen in deze richting.
I run a a development team and we're working on some functionality that we're likely going to share between different projects. The problem is that part of the functionality are some adminstration pages that we want to be able to develop separately, deploy as part of customer's. The requirements we have are roughly the following
- We can version the pages separately, so that when we patch the shared functionality, we don't have to rebuild/redploy the entire site.
- We don't have to copy files from one project (the project with shared functuionality) to another (the project that is customer specific).
- In our source control the customer's website is really a separate project and not a branch of the project with shared functionality.
- The administration pages should be themed to the customer's site and additional admin pages may be added custom for the customer's website.
The best way, we figured, was to deploy the shared functionality as a seprate assembly, similar to a precompiled website. A precompiled website however is one thing, AFAIK you can't dump two precompiled websites into the same application. I did figure out a way to deploy the site as an assembly, by putting the admin pages inside an assembly as an embedded resource. We then pull the pages out using a VirtualPathProvider. There are great implementations out there using the VirtualPathProvider, such as serving a website from a ZIP-file and from a database (which is what SharePoint does).
If you don't know what a VirtualPathProvider is, let me quickly fill you in. When ASP.NET gets an aspx page for the first time, compiles that page and stores the result in a system directory. Only when you change the file will ASP.NET recompile the page. Now, the file system that ASP.NET gets the page from is virtualized, which means that ASP.NET does not know how the underlying file system is implemented. By default this is the normal Windows file system, but you can create a provider that uses another storage mechanism. As long as it works just like the file system, this will work fine. You can use a database, XML file, ZIP file, web service, or whatever as the underlying file system. All you have to do is create a few classes, including an implementation of the VirtualPathProvider, register the provider in global.asax, and you're off. The great thing is that because you're supplying ASP.NET with the page, your page benefits from ASP.NET (pre)compilation. This means that if you build a CMS with content in a database, the database is only hit the first time the page is requested and the content is compiled into the page.
So, what we can do is put the aspx pages inside an assembly as an embedded resource and serving the pages from there. Because the pages are inside a regular .NET assembly, it can be linked into a project and be updated when there is a patch, without affecting the application's it is contained in. All we have to do is redeploy the assembly. It sounds a bit weird, but it actually works, as you can see in the attached demo (51.54 KB). Be aware that this is really just a demo. It is just meant to prove it works. The logic to get directories is flawed (which has something to do with the fact that directories are not preserved in embedded resources), and possibly more is. However, you can access the following pages:
- \AdminHome.aspx
- \Default.aspx
- \NewFolder1\HTMLPage1.htm (only works in VS webserver or IIS7 in integrated mode)
Default.aspx is kind of funny, because the code behind class is compiled in the class and the page itself embedded. Enjoy!
Ik kan soms best vergeetachtig zijn. In dit geval wel schandelijk, want ik ben volkomen vergeten te melden dat ik een nieuw boek uit heb: ASP.NET 3.5 - de basis. Net als z'n voorganger ASP.NET 2.0 - de basis een boek om te leren werken met ASP.NET. Het is gebaseerd op z'n voorganger, maar bevat behoorlijk wat nieuw materiaal over o.a. ASP.NET AJAX en Language Integrated Query (LINQ). Uiteraard komen ook de nieuwe ASP.NET server controls aan bod.
JavaScript Intellisense in Visual Studio 2008 is een prachtig stukje demoware. Het lijkt op het eerste gezicht allemaal heel aardig te werken... totdat je er zelf echt mee aan de slag gaat. En met "echt" bedoel ik voor productie, niet die leuke demotjes. Dan loop je tegen zoveel problemen aan dat je wat mij betreft moet concluderen dat het (op z'n zachts gezegd) "nog niet biedt wat je ervan zou verwachten". Ik heb al heel wat tijd verspijkerd om de comments van mijn scripts goed te krijgen, zodat VS ermee overweg kan. Niet zelden zonder het gewenste resultaat. Deze blogpost van OpenSource Connections geeft een goede opsomming van wat ik bedoel.
Jeff Prosise made a nice blog entry about hiding the root node in the SiteMapPath-control. Some people, like myself, experienced an issue when the current node and the root node ar actually the same. Somehow the check that should avoid that issue fails. I believe because the current node is in fact a clone of the current node, and as such not equal to the current node (i.e. root node) itself. To get around this, I have changed the code somewhat to do the check on the actual nodes. The body of the HideRootNode-method is now as follows:
// Return root node in case this is the root. if(SiteMap.RootNode == SiteMap.CurrentNode) return SiteMap.CurrentNode;
// This is not the root node, so rebuild path without root. SiteMapNode node = SiteMap.CurrentNode.Clone(); SiteMapNode current = node; while (node.ParentNode != SiteMapNode.RootNode) { node.ParentNode = node.ParentNode.Clone(); node = node.ParentNode; } node.ParentNode = null; return current;
Thanks to Jeff for his original insight. It saved me a lot of time.
Visual Web Developer 2005 has a great feature for graphically impaired people like myself. In a page you could go to the Layout menu and select Insert Table. The dialog then had all sorts of table templates (see picture). In the 2008 version this dialog (in fact the entire Layout menu) is gone and replaced by a run-of-the-mill insert table dialog. Why on earth did Microsoft take this out?

For those interested in the demo of Using Windows Workflow Foundation in ASP.NET, you can download it here (269 kb). Note: this is the demo with the "double bookkeeping". The request/response inside a workflow isn't stable enough yet for release.
For those people interested in the demo's I did in the session Create Scalable Apps with Async Processing at VSLive! this week, you can download here (600 KB). To "install" the demo's, create a Visual Studio solution with two websites (one for each folder in the zip file). Run the web service to get a port number, then update web.config in the AsyncPages folder so that web services reference that port number (or take the port number currently in web.config and set the web service to run on the specified port). Enjoy!
I'll be at VSLive! in Las Vegas next month. On Tuesday, October 16th, I'll be speaking about two topics:
- Using Windows Workflow Foundation in ASP.NET
- Create Scalable Apps with Asynchronous Processing
The first is an introductory session about Windows Workflow Foundation (WF) and adresses how to deal with WF in ASP.NET. Because WF is not request-response by nature, this is more challenging than you would think. The second session discusses ASP.NET 2.0 Async Pages and Handlers and shows you how to use this with web services and databases.
Hope to see you there!
MOSS 2007 has it's own theming engine, separate from the ASP.NET theming engine. A downside of the MOSS approach is that you require an IIS reset to change a theme. Not very nice, so we wanted to use ASP.NET theming instead. This however causes problems with all pages in the _layouts folder, because they don't have <header runat="server" />. That tag is necessary, because ASP.NET needs to add CSS references and such to the <head> tag. Without that tag you receive the following error message:
Using themed css files requires a header control on the page
The solution is to define no theme for the pages in the _layouts folder. Since the pages in that folder are mainly dialog-type screens for SharePoint operations, this is not a problem from a look & feel perspective. That said, there are situations where you create your own pages and put the in the _layouts folder. For those pages you can apply a theme, providing there are no (MOSS) webparts and such on the page. In web.config this would look something like this: <location path="_layouts">
<system.web>
<pages theme="" />
</system.web>
</location>
<location path="_layouts/MyCustomPage.aspx">
<system.web>
<pages theme="MyTheme" />
</system.web>
</location>
Last year I wrote a book (in Dutch) about ASP.NET 2.0. For that book I did an interview with Scott Guthrie, General Manager of the .NET Developer Platform group at Microsoft. In the book the interview is of course translated and also edited to fit the book. Below is the original unedited version.
Who are you? My name is Scott Guthrie. I am the General Manager of .NET Developer Platform group within Microsoft, which means I run the development teams that build the CLR, .NET Compact Framework, ASP.NET / Atlas, Windows Presentation Foundation (aka Avalon), Windows Forms, IIS 7.0, Commerce Server, and the Visual Studio development tools for ASP.NET and WPF.
How long have you worked for Microsoft, and in what did you do up to becoming General Manager? I’ve been at Microsoft for 9 years. I’ve been focusing on frameworks, tools and servers for developers pretty much the entire time. Prior to my current role, I ran the teams that built ASP.NET, IIS 7.0, and Visual Web Developer.
You are generally seen as the (co-)creator of ASP.NET. How was ASP.NET conceived and where did you get the ideas from? We actually started the ASP.NET project in late 1997 and early 1998. At the time ASP was still relatively new, and we initially weren’t sure whether there was anything left to-do in the web space (little did we know)! We then spent a lot of time talking with developers and customers using ASP and quickly realized that there were a lot of things left to resolve.
Some specific issues/requests that came up again and again from customers: provide the ability to write much cleaner code that provided good code/content separation (rather than mixing code up in the HTML), provide the ability to write applications using a variety of coding languages (and not just VBScript and Jscript), deliver a more robust execution environment (avoiding memory leaks and crashes that could bring down the server), provide a much cleaner configuration/code deployment model, deliver a built-in security architecture, enable built-in output caching support to improve scalability, and more.
A colleague of mine (Mark Anders) and I spent about 2 months brainstorming ideas about how we could build a programming model that delivered all of this. Eventually we decided we needed to put together a prototype to try out the concepts, and I ended up coding it up over the Christmas and New Year’s holiday in 1997/98 (I was a hardcore geek then <g>). We showed off the prototype to a lot of people within the company, built a lot of excitement, and got the go ahead to build a team to deliver it.
What are the main differences between ASP.NET 1.x and ASP.NET 2.0? We spent a lot of time working with customers to identify where they spend their time writing code today within web applications, and then worked to add new features in ASP.NET 2.0 to help simplify these tasks dramatically. Some examples: Master Pages allow you to easily define a consistent layout across your site/application, the new Membership/Roles API provides an easy way to manage users/passwords/roles and allows you to build flexible secure application in only a few minutes, the new GridView/DetailsView/DataSource controls enable you to easily provide data entry and editing views on top of data (including 3-tier data access support), Web Parts provide the ability to enable portal-style layout within any page and enable drag/drop end-user customization that works both in regular ASP.NET applications and SharePoint solutions, Localization support has been added to make it much easier to build multi-lingual applications that can adjust at runtime depending on the culture/language of the incoming user, SQL Output Caching enables developers to output cache any content within a site and have it automatically be invalidated and re-generated when backend data changes on a site (dramatically improving performance), Site Navigation and Menu controls make it much easier to build menu structures and navigation across your sites, Health Monitoring makes it easier to monitor how your application is doing once it is deployed, and there are many more features I could keep calling out.
If you could give one tip to people learning ASP.NET 2.0, what would it be? I’d recommend spending time on the new http://www.asp.net web-site in the “Getting Started” and the “Learn” sections. We are putting out several new videos and tutorials each week on the site that help show how you can take best advantage of new features with ASP.NET. These can make it significantly easier to take full advantage of the platform and build great applications. I’d also recommend subscribing to my blog: http://weblogs.asp.net/scottgu. I try and post 1-2 tips/tricks a week that you can use.
What do you (personally) think is the coolest feature of ASP.NET 2.0? Master Pages is probably the most popular feature that virtually everyone takes immediate use of – so in terms of popularity that is probably the coolest.
I think the new ASP.NET 2.0 AJAX Extensions product we are shipping later this year is also really, really cool (note: this was formerly codenamed “Atlas”). This will provide a free, fully-supported AJAX library with suite of ASP.NET 2.0 server controls that enable you to easily add AJAX functionality to your ASP.NET 2.0 sites.
What are the long term goals for ASP.NET, and what will we see of that in the coming years? The next release of ASP.NET will have a lot of great additions. You will see even richer support for the AJAX Extensions built-into the next release, as well as much richer support for building more interactive user experiences that take full advantage of the browser.
You’ll also see ASP.NET take advantage of the new LINQ technologies that are coming out with .NET, and which will enable really rich data modeling and mapping support with code which will dramatically improve the productivity of working with data. When LINQ is combined with the ASP.NET 2.0 GridView, DetailsView and other data controls, you have a tremendously easy and powerful programming model for building AJAX enabled data applications. I’m really excited to see the applications people build with it. It is going to be a very exciting future!
Dino Esposito gaf vanmorgen een sessie over Async Pages in ASP.NET. Toevallig heb ik op VSLive een vergelijkbare sessie gedaan en Dino wist dat ik daar een demo in heb zitten die laat zien wat de schaalbaarheids voordelen zijn van Async Pages. Dino is een goede bekende van me en hij nodigde me uit om mijn demo aan het eind van zijn sessie te doen. Het was leuk om weer eens met Dino op het podium te staan en wat toe te kunnen voegen aan zijn verhaal. De demo code is te vinden bij de demo's van VSLive. De tool die ik gebruikte was Application Center Test van Visual Studio 2003. Ik vind die tool handiger voor dit soort tests dan de tools in VS2005.
De dag na DevDays organiseert DevConnections twee workshops:
- ASP.NET AJAX Extensions Inside Out door Dino Esposito
- Optimising and best practices for all SQL Server 2005 features door Bob Beauchemin
Als je nog wat wilt leren na DevDays, dan is dit een hele goede kans. Beide sprekers kennen het onderwerp van haver tot gort, dus het is zeker de moeite waard. Nog niet helemaal overtuigd? Bob en Dino spreken allebei op DevDays, dus als je daar bent kun je eerst even een kijkje nemen. Je kunt je op de DevDays eventueel ook inschrijven voor een van de workshops.
I've been working with ASP.NET 2.0 for a long time now and I thought I'd seen most of it. Today I found something that must have flown under my radar all this time: the Health Monitoring API. Functionally this API is similar to log4net and the Enterprise Library logging Application Block. Although both of these work well I prefer functionality that comes "out-of-the-box", because you don't have to do anything to get it, it works, and your pretty sure it'll be kept up to date by the folks in the product team(s). So even if you're using another logging mechanism, be sure to check out the Health Monitoring API. How To: Use Health Monitoring in ASP.NET 2.0 from the Pattern & Practices group is a good starting piont.
Ik werk al zo lang met ASP.NET 2.0 dat ik dacht alles wel een keer gezien te hebben, maar nu blijkt er toch iets aan mijn aandacht ontsnapt te zijn: de Health Monitoring API. Deze API is qua functionaliteit vergelijkbaar met log4net en het logging Application Block van Enterprise Library. Hoewel dat beide goede logging biedt ben ik toch altijd wel een voorstander van functionaliteit die "out-of-the-box" beschikbaar is, omdat je daarmee zekerder bent van de levensduur en bugfixes. Ook als je een ander loggingmechanisme gebruikt is het dus zeker de moeite waard om even naar de Health Monitoring API te kijken. Een goed startpunt is How To: Use Health Monitoring in ASP.NET 2.0 van de Pattern & Practices groep.
Thanks to all that came to my sessions at VSLive in Orlando on Tuesday, and thanks for the great feedback. Below are the demo's for the two sessions. Updated slides decks will be made available on the attendee website.
Some of you asked which tool I used to demo the perf difference between sync and async (demo 1). Although you could use perf tools that come with VS2005 I used Application Center Test (ACT) that comes with Visual Studio 2003, because it is very easy to setup and shows nice graphics (which was most important for this demo). You can also use the free Web Application Stress Tool. The ACT script I used was (substitute "slow.aspx" with "slowasync.aspx" for the async test), with 50 browser connections:
Randomize() If Rnd(10) < 5 Then Test.SendRequest("http://testserver/Demo01/Fast.aspx") End If Test.SendRequest("http://testserver/Demo01/Slow.aspx") Test.SendRequest("http://testserver/Demo01/Fast.aspx")
Note: I've run this test in several setups with different hardware. In my Orlando session I showed numbers from ACT on the host to the web in a VPC. In my San Francisco session ACT was on a Dell D600 with the web running in a VPC on my Dell D800, which is a better way to test (in the Orlando setup ACT is drawing perf from the same CPU). The async perf is much better (even in percentages) with the SF setup. Be aware that there are a lot of variables: CPU capacity, memory, and last but not least... network interface. In another test setup I hardly saw any difference between sync and async. Why? Because the network was the bottleneck :(.
Wil je meer weten over Silverlight? Dan is silverlight.net een goed startpunt, met onder andere een aantal video tutorials. Een aantal sessies van de MIX conference en meer informatie over Sliverlight kun je vinden in deze blogpost van Scott Guthrie. Scott Hanselman heeft daarnaast een lijst met voorbeelden verzameld in zijn post Silverlight samples.
Windows "Longhorn" Server Beta 3 is te downloaden van het MSDN Evaluation Center. Onderdeel van deze release is ook IIS7 die te gebruiken is met een Go Live License. Dat betekent dat je er mee in productie mag gaan, maar wel voor eigen risico. Meer over de mogelijkheden van IIS7 is te lezen in deze blogpost of op www.iis.net.
Download the demo's here (34.39 KB)
During the session I promised to give put a sample here about using delegates for asynchronous processing, but what's the use if you can just read it on MSDN: Calling Synchronous Methods Asynchronously. Again, be aware that you shouldn't use this in ASP.NET!!! This is for console, desktop, and Windows Services only! In ASP.NET this would exhaust the thread pool pretty fast.
Download the demo's here (85.85 KB). If you want the slides, send me an email.
If you want to do the AspCompat demo, don't forget to register the VB6 component from the command line with regsvr32.
Ik zie in code geregeld dat het Session object op allerlei plaatsen gebruikt wordt, met name in pagina's en controls, als volgt:
public void Page_Load(object sender, EventArgs e) { Session["MySessionVar"] += 1; }
public void Page_PreRender(object sender, EventArgs e) { Label1.Text = Session["MySessionVar"].ToString(); }
Dit is om meerdere redenen niet aan te raden:
- Omdat de collectie loosely typed is, is er geen compile-time check bij het benaderen van de elementen in de collectie. Het is daarom heel makkelijk om een typfoutje te maken, waardoor je tegen het verkeerde object aan praat.
- Door elementen in het Session object te stoppen in de pagina, is er geen centrale administratie van de namen (keys) die in gebruik zijn.
Je kunt beide zaken oplossen door een centraal object te maken waarmee je de elementen in het Session-object benaderd, als volgt:
/// <summary> /// Strongly typed toegang tot Session-object. /// </summary> internal static class TypedSession { public static int MySessionVar { get { object o = HttpContext.Current.Session["MySessionVar"]; if(o == null) return 0; return (int)o; } set { HttpContext.Current.Session["MySessionVar"] = value; } } }
public void Page_Load(object sender, EventArgs e) { TypedSession.MySessionVar += 1; }
public void Page_PreRender(object sender, EventArgs e) { Label1.Text = TypedSession.MySessionVar.ToString(); }
Merk op dat bij de get-accessor eerst gekeken wordt of het object null is. Dit is nodig omdat een int niet null mag zijn. Voor objecten waarvoor dat wel mag kun je desondanks besluiten dat er een standaardwaarde moet zijn, bijvoorbeeld een nieuw object.
Deze methodiek werkt ook uitstekend voor de Request.QueryString collectie en meer van dat soort collecties die je normaal gezien loosely typed gebruikt. Die zal je niet zo snel centraliseren, omdat het juist op een bepaalde pagina van toepassing is, maar daarmee strongly typed kunnen werken is nog steeds minder foutgevoelig. Bovendien hoeft de ontwikkelaar niet te weten waar de data vandaan komt.
Onlangs kreeg ik de volgende melding in Visual Studio 2005: The project file ' ' has been renamed or is no longer in the solution. Hierdoor was het niet meer mogelijk om ook maar iets van het project te bouwen. Het vervelende aan dit probleem is dat je geen idee hebt wat er nu eigenlijk aan de hand is. Na enige tijd vond ik uit dat dit gebeurt als een Web Project referenties bevat naar assemblies of projecten die het niet kan vinden. Je lost dit als volgt op:
- Rechts-klik op het Web project en kies Property Pages.
- Er verschijnt een venster met alle referenties, zowel naar de bin-map, GAC of andere projecten in de solution.
- Verwijderer de referenties gemarkeerd met (unavailable).
- Waarschijnlijk kun je nu niet bouwen omdat je assemblies mist. Als je de referenties daar naartoe maakt zou alles moeten werken.
We were recently faced with the error message The project file ' ' has been renamed or is no longer in the solution in Visual Studio 2005. The problem is that from this message you have no idea what is actually the matter. We finally figured out that this happens when a Web Project contains references to assemblies or projects it can't find. Here's how you solve this:
- Right click the Web project and select Property Pages.
- A window will open which lists all the references, either to the bin-folder, GAC or other projects in the solution.
- Remove those that show (unavailable) behind it.
- Chances are that now you can't build because the reference is not there. Simply add the reference again and you should be OK.
Hoera! ASP.NET Ajax 1.0 is beschikbaar. Met ASP.NET Ajax kun je pagina's maken die alleen die delen van de pagina verversen die ook daadwerkelijk gewijzigd moeten worden. Dat scheelt netwerkverkeer, maar maakt bovendien de gebruikerssinterface veel mooier.
Maar, het is nog beter. Microsoft geeft ook de source code vrij van ASP.NET Ajax! Je kunt de source code hier downloaden. De source code wordt uitgegeven onder de Microsoft Permissive License (Ms-Pl), die het toestaat om de broncode aan te passen en in aangepast vorm te gebruiken en te verspreiden. Dat smaakt dus min of meer als open source.
Van 25 t/m 29 maart is in San Fransisco VSLive (ASPLive) waar ik twee sessie ga doen over ASP.NET:
- Understanding Multi-Threading (in ASP.NET)
- Creating Scalable Apps with Asynchronous Processing
De eerste sessie gaat in op het feit dat ASP.NET een multi-threaded omgeving is en bekijkt wanneer en hoe dat relevant is voor ons als (web) ontwikkelaars. De tweede sessie bespreekt asynchronous pages, handlers en modules, waarmee je de schallbaarheid van je applicatie kunt verbeteren zonder extra hardware. Zie voor meer informatie de sessieomschrijvingen op de site van VSLive.
I've been invited to speak at VSLive in San Fransisco ASPLive from March 25 to March 29. I will be doing two sessions on ASP.NET:
- Understanding Multi-Threading (in ASP.NET)
- Creating Scalable Apps with Asynchronous Processing
The first session takes a closer look at the fact that ASP.NET is a multi-threaded environment and what that means for us (web )developers. The second session looks at asynchronous pages, handlers and modules, to increase the scalability of our apps without adding new hardware. For more information checkout the session abstracts on the VSLive site.
I hope to see you there.
Since January 1st Slovenia is using the Euro, so all e-commerce need to change to the euro. More accurately, the culture settings for Slovenia in Windows need to be changed. Unfortunately there is no patch available yet for Windows and you can't change the settings through the Configuration Panel (it'll change back automatically). Until the patch arrives, the following code can remedy the situation:
CultureInfo culture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone(); culture.NumberFormat.CurrencySymbol = "€"; culture.NumberFormat.CurrencyPositivePattern = 2; // € 19.95 culture.NumberFormat.CurrencyNegativePattern = 12; // € -19.85 Thread.CurrentThread.CurrentCulture = culture;
This changes the culture settings at thread level. Adding this to Application_BeginRequest in global.asax works like a charm, but don't forget to check the initial culture first...
Sinds 1 januari gebruikt slovenie de euro en dus moeten alle e-commerce sites over op de euro. Of eigenlijk beter gezegd, de culture settings van Windows moeten nu gebruik maken van de euro voor Slovenie. Helaas is dit niet aan te passen (verandert automatisch terug) en zou er dus een Windows update moeten komen. Zolang die er niet is, moet je de standaardinstellingen overschrijven. Dit kan met de volgende code:
CultureInfo culture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone(); culture.NumberFormat.CurrencySymbol = "€"; culture.NumberFormat.CurrencyPositivePattern = 2; // € 19.95 culture.NumberFormat.CurrencyNegativePattern = 12; // € -19.85 Thread.CurrentThread.CurrentCulture = culture;
Hiermee wordt op thread niveau de CultureInfo aangepast. Deze zet je tijdelijk in Application_BeginRequest van global.asax en dan werkt het prima. Overigens niet vergeten of the thread wel Sloveens is om mee te beginnen...
Visual Studio 2005 SP1 is beschikbaar. Het lost allerlei bugs op en biedt een aantal verbeteringen, waaronder - Nieuwe project types voor ASP.NET
- Ondersteuning voor nieuwe processor types voor code generatie en profiling
- Integratie van Excel 2007 en Project 2007 met Team Foundation Server
- Ondersteuning voor Windows Embedded 6.0 platform en tools
Meer informatie is te vinden op de MSDN pagina Visual Studio 2005 Service Pack 1 (SP1).
Microsoft heeft een security patch uitgebracht voor Visual Studio. Het "gat" in VS2005 wordt als kritiek beschouwd, dus is het heeeel verstandig de patch te installeren. Zie voor meer informatie en download Microsoft Security Bulletin MS06-073.
Nu Internet Explorer 7 uitgerold wordt op de meeste computers ontstaat de situatie dat sites zowel met IE6 als IE7 goed moeten werken. Dit testen vanaf 1 machine is lastig omdat IE7 over IE6 heen gezet wordt. Maar geen nood, je kunt altijd nog gebruik maken van Virtual PC om in een virtuele machine met IE6 te testen (of IE7 natuurlijk als IE6 op je eigen machine staat). Microsoft biedt hiervoor een kant-en-klare Virtual PC. Meer informatie en de nodige download links vind je op het IEBlog. Bij The Vision Web werken we al tijden met Virtual PC voor het ontwikkelen en testen van applicaties, dus waren we zelf ook al op deze oplossing gekomen. Het is echter wel erg handig dat Microsoft een standaard Virtual PC aanbiedit hiervoor.
Vandaag ontving ik met de post het eerste exemplaar van mijn nieuwe boek ASP.NET 2.0 - de basis. Het ziet er mooi uit en ik ben er dan ook trots op. Het behandelt de beginselen van ASP.NET 2.0 op zo'n manier dat je na het lezen van het boek ook echt wesites kunt maken met beveiliging, gegevens in een database, gebruikersprofielen en nog meer. Het boek is uiteraard verkrijgbaar via de boekhandel en diverse websites, maar kan ook besteld worden bij uitgever Pearson Education.
Ik wil bij deze alle mensen die meegewerkt hebben aan het boek hartelijk bedanken. John Numan die mij gevraagd heeft het boek te schrijven, Sandra Wouters die alles in goede banen geleid heeft en Cynthia van Heusden voor de tekstcorrectie. Tenslotte ben ik een enorme dank verschuldigd aan mijn vrouw Annette. Niet alleen voor haar tekstcorrectie en suggesties om het boek beter te maken, maar ook voor ruimte die ze me gegeven heeft om het boek te schrijven.
Commerce Server is een van die producten die altijd net buiten m'n gezichtsveld ligt. Binnen The Vision Web hebben we een aantal experts op het gebied, dus het is niet echt nodig om me daar mee te bemoeien. Nu CS2007 gebaseerd is op ASP.NET 2.0 weet ik echter ineens veel meer van de algemene werking dan voorheen. Door het baseren op ASP.NET 2.0 is CS2007 overigens niet meer bruikbaar met ASP, omdat er geen COM interfaces meer zijn. Die zou je wel weer kunnen maken door de Web Services interface te wrappen, maar dat moet je niet willen.
De spreker (Ryan Dononvan) weet waar hij het over heeft, maar dat mag ook wel als je onderdeel bent van het team dat het maakt. Wel lopen z'n demo's nog redelijk stroef. Dat een iisreset nodig is om een nieuw thema (look & feel) toe te passen vind ik wel dubieus. Een half uur in de sessie heb ik alleen nog maar ASP.NET 2.0 dingen gezien, met uitzondering van de standaard globalization zaken.
Wat me vooral opvalt is dat CS2007 niet een beetje, maar echt veeeeel beter doordacht is dan z'n voorloper. Het is niet meer een verzameling losse handige tools, maar veel meer gericht op het proces. Zo kunnen allerlei business rules gedeeld worden tussen verschillende onderdelen, zodat je niet meer op meerdere plaatsen dezelfde rules moet implementeren. De BizDesk is ook weg en vevangen door een Windows SmartClient applicatie die communiceert via de Web Services interface. De code van de SmartClient is beschikbaar in de Partner SDK en je kunt 'm daarom aanpassen aan eigen wensen. Dat geldt ook voor de rapportage, omdat die gedaan wordt via Reporting Services. Gek genoeg voor zowel SQL 2000 als SQL 2005, terwijl CS2007 alleen draait op SQL 2005 (althans dat zei Ryan eerder in z'n presentatie).
Tip voor de spreker (demo's geven les 1): zorg dat je alle updates geinstalleerd hebt en zet auto update daarna uit! Nu moest hij wachten tot zijn VPC opnieuw opgestart was na het installeren van updates.
When you make columns invisible in a GridView-control the values in those columns are ignored when doing an update. If the update function, stored proc, or whatever expects these values (particularly when you use CollisionDetection="CompareAllValues"), the update will fail.
The solution: - Add the names of the invisible columns to the DataKeyNames-properties separated by a comma, so the values are available. - Create an event handler for the GridView.RowUpdating and add the code below. This copies all "key" values to the old and new values so the update will work.
IDictionaryEnumerator restoreOldValues = e.Keys.GetEnumerator(); while (restoreOldValues.MoveNext()) { e.OldValues.Add(restoreOldValues.Key.ToString(), restoreOldValues.Value.ToString()); e.NewValues.Add(restoreOldValues.Key.ToString(), restoreOldValues.Value.ToString()); }
Als je kolommen onzichtbaar maakt in een GridView-control worden de waardes daarvan niet meegestuurd als je een update gaat doen. Als je werkt met CollisionDetection="CompareValues" betekent dit dat de update niet goed gaat als de stored procedure of functie die je gebruikt de originele waardes ook verwacht.
De oplossing: - Voeg de kolommen die je niet zichtbaar maakt (of uberhaupt niet invoegt) toe aan de DataKeyNames-eigenschap, gescheiden door een komma. - Maak een EventHandler voor GridView.RowUpdating en zet daar de onderstaande code in. Hiermee worden alle keys toegevoegd aan de oude en nieuwe waardes (die voor die kolommen toch niet verandert).
IDictionaryEnumerator restoreOldValues = e.Keys.GetEnumerator(); while (restoreOldValues.MoveNext()) { e.OldValues.Add(restoreOldValues.Key.ToString(), restoreOldValues.Value.ToString()); e.NewValues.Add(restoreOldValues.Key.ToString(), restoreOldValues.Value.ToString()); }
I was looking for something totally different, but came across this article on the Oracle Technology Network about the differences between PHP and ASP.NET. First of all I was sort of puzzled by the obvious pro-PHP stance taken by Oracle (at least in this article). I expect Oracle to be biased towards Java, which their product line supports, but as far as PHP and ASP.NET are concerned they're just web technologies and both can use Oracle. As long as Oracle is used, what does Oracle care which of the two technologies is used? Secondly the pro-PHP bias I mentioned is very obvious if you look at the comparisons of speed and security. PHP faster than ASP.NET? I don't think so... and most tests seem to agree with me. The argument Sean Hull uses is that ASP.NET is much bulkier when it comes to the actual code being executed. Maybe so, but the CLR compiles and optimizes that plenty. Then when it comes to security Sean Hull comments that ASP.NET runs on IIS, which according to him must be qualified as unsafe because of its history. He goes on to comment that Apache is much safer. I guess he forgot to check the latest stats on securityfocus.com and secunia.com. The number of vulnerabilities in IIS6 found in its entire existence is 3 (or 5, depending on how you count), compared to the 32 (or 39) found in Apache 2.x during rougly the same period I would say IIS looks pretty good. Looking at the same timeframe (2003-2006) even IIS5 has had less vulnerabilities (14). 3+ years is quite a long time when it comes to the web, so history in that sense gives the edge to IIS, not Apache. Looking at the stats that is, the sentiment (or perception if you will) is still that IIS is (or could be) unsafe. I guess the time it takes to change someones perception is longer than 3+ years, so I guess Microsoft must battle perceptions that are nog longer justified.
Recently one of my collegues was trying to create a Web Setup project for an application in VS2005 and he commented "I can't add the Primary Output of the application to the setup, just the content." This is where VS2005 (or actually ASP.NET 2.0) differs from VS2003, so I explained that this was normal behavior and that his application didn't need to have an application assembly because ASP.NET 2.0 compiles everything on the fly. His reply was that you wouldn't want to have your source code sitting in the production enviroment, and he is absolutely right. The solution to this is precompiling your applications with aspnet_compiler.exe. This packages all your files, inlcuding the contents of your .aspx files in an assembly which is used to run the site. The .aspx files are still there, but these are just placeholder files with no contents. By default the .aspx files can't be edited (well, you can but that doesn't change what is sent to the browser), but this can be controlled. Checkout the MSDN article How to: Precompile ASP.NET Web Sites for Deployment on how to use aspnet_compiler.exe. For a complete rundown of precompilation see ASP.NET Web Site Precompilation.
Met behulp van Typed DataSets en TableAdapters kun je een volwaardige Data Access laag maken voor je applicatie, en kun je met behulp van de ObjectDataSource control de nodige data in je applicatie tonen en bewerken. Hoe je dit allemaal kunt doen (en nog veel meer) is te lezen in een serie tutorials geschreven door ASP.NET guru Scott Mitchell.
Het scenario: Een bestaande applicatie schrijft (Word) bestanden in een image-field in een SQL Server database, en jij moet ze er weer uithalen en naar een browser sturen.
De oplossing: Je zou zeggen "no problemo", met een DataReader kan ik bytes uit het betreffende veld lezen, en als ik gebruik maak van een DataAdapter+DataSet dan heb ik de hele byte array. Vervolgens gebruik je gewoon Response.BinaryWrite. Dat dacht ik eerst ook, totdat ik het deed en Word niet met het bestand overweg bleek te kunnen.
In dit saoort gevallen is een HEX viewer onmisbaar. Trek een bestaand document open en kijk hoe die er op byte niveau uitziet, en doe hetzelfde met het foute bestand. In mijn geval viel op dat we dezelfde karakters erin stonden, maar in het foute bestand staat een extra byte tussen alle karakters. Het foute bestand maakt dus kennelijk gebruik van 16-bits karakters, vermoedelijk UTF-16 (Unicode). Om dat te verhelpen kun je gebruik maken van de System.Text.Encoding class:
Encoding.Convert(Encoding sourceEncoding, Encoding destinationEncoding, byte[] sourceByteArray);
Mijn eerste gok was UTF-16 naar UTF-8, maar dat bleek niet goed te zijn. Ook de andere in .NET bekende encodings (UTF-7, ASCII) leverden niets op. Terug naar de Windows code pages dus... Mijn eerste gok was meteen goed: windows-1252, waardoor de code hieronder het gewenste resultaat leverde (GetDocument is een functie die en byte array teruggeeft van het bestand in de database):
Encoding targetEncoding = Encoding.GetEncoding(1252); Response.Clear(); Response.ContentType = "application/ms-word"; Response.AddHeader("Content-Disposition", "attachment;filename=bestand.doc"); Response.BinaryWrite(Encoding.Convert(Encoding.Unicode, targetEncoding, DocDataAccess.GetDocument(documentId)));
Relationele data en objecten passen over het algemeen niet echt lekker op elkaar. Daarom zijn er ook behoorlijk wat Object-Relation Mapping tools (O/R Mappers) op de markt. Met LINQ en DLINQ brengt Microsoft relationele data en objecten dichter tot elkaar. Scott Guthrie heeft twee uitgebreide blog posts gemaakt over hoe dit in ASP.NET gebruikt kan worden. Zie Using LINQ with ASP.NET (Part 1) en Using DLINQ with ASP.NET (Part 2 of my LINQ series)
The recent post by Scott Guthrie on Localization in ASP.NET 2.0 made me realize that most developers I know (myself included) don't know that much about localization. That's kind of ironic because I live in The Netherlands where the primary language is definitly not English. You would expect that in countries like that localization would be a big issue. It is not (well not here anyway).
Aangezien wij niet in een Engelstalig land wonen zou localisatie van applicaties voor ons best belangrijk moeten zijn, maar in de praktijk weten weinig mensen er echt goed mee overweg te kunnen (mezelf incluis). Scott Guthrie heeft op zijn blog een bericht met allemaal goede informatiebronnen hierover, waaronder een webcast van 13 minuten. Zie ASP.NET 2.0 Localization (Video, Whitepaper, and Database Provider Support)
|