Friday, April 25, 2008
DevConnections Orlando Slides and Demos
I spoke this week at DevConnections in Orlando. As always a great time and a good show. For those that attended my talks, thanks for the great participation and questions! For those that didn't, you really need to work harder on convincing your boss to send you to a DevConnections conference. The line up of speakers is amazing and the venue is always great.
The three talks I gave were on building custom activities in WF, WPF Tools, and Service Oriented workflows.
You can grab the slides and demos from the links below.
Custom WF Activities: Slides Demos
WPF Tools: Slides
SO Workflows: Slides Demos
Enjoy!
.NET | Speaking  Friday, April 25, 2008 12:10:20 AM (GMT Daylight Time, UTC+01:00)  |
Thursday, June 14, 2007
Developing Applications with Windows Workflow Foundation LiveLesson
My latest publishing project, which I haven't talked about much on the blog, is a LiveLesson training DVD on WF. This product has now released and you can find all the details here:
http://www.awprofessional.com/title/0321503139
It contains about 5 hours of video instruction on the breadth of WF, including sequential workflows, state machine workflows, showing how to use each of the base activity library activities, how to communicate with workflows, how to handle exceptions, custom activities, and much more. Because of the length of the instruction, it is more of a shallow dive into each of the topics to get you started, rather than being very deep in any one area. The content is mostly Camtasia screen capture while demonstrating the techniques being discussed.
There is also a sample lesson available through YouTube:
http://www.youtube.com/livelessons
If you are getting started using WF, this would be a good way to get bootstrapped.
Spread the word!
Wednesday, June 13, 2007
Slides and demos from Cleveland .NET SIG
I gave a talk on WPF for ASP.NET developers this evening at the .NET SIG in Cleveland. Good size crowd and great questions. It was a challenging talk because of trying to cover all of WPF and Silverlight for ASP.NET developers and for those in the crowd who were Windows Forms developers.
I covered the various deployment models of WPF including:
- Windows Application
- XAML Browser Application (XBAP)
- Plain Old XAML Page (POXP?)
- Silverlight App
Whenever I present this stuff, the overwhelming reaction is: Stop giving us so many choices!!! We can't figure out what to use when!
There is also often a desire for a conclusion to be drawn that one of these will be the end state and all UI will be written in it. I just don't think that will be the case. I think that maybe 5 years from now, if the tools come along a lot farther than they are now, and if the control suite grows, the list of options could shorten to just WPF Windows App, Silverlight App, and ASP.NET AJAX app. But I don't think it will shrink beyond that. Windows Apps make sense when you control the desktop to take maximum advantage of the client platform and give the best user experience. Silverlight makes sense for broader reach while sticking to the same tools and programming models. ASP.NET AJAX will be broader still and will address the platforms that Silverlight can't reach, and will also (like Windows Forms) be more evolved for data over forms apps for a while to come.
Anyway, here are the slides and demos for those who are interested:
Slides Demos
Monday, April 30, 2007
Silverlight - not just pretty graphics - Cross platform .NET Framework!
Watching Scott Guthrie's keynote at Mix07 right now. The word is finally out - and wow. Silverlight is not just a Flash alternative - it is a cross platform, cross browser .NET runtime and framework. C#, VB, any .NET language driving display in the browser, running on the client side, on other platforms.
Beta for 1.0 is out today, available on www.silverlight.net.
You can even debug cross platform with the .NET code running in a Mac browser. I think we are not far from stepping through the time space continuum now...
Saturday, April 28, 2007
Monday, March 26, 2007
DevConnections Orlando - a tale of three sessions
I've arrived in Orlando and am looking forward to giving my sessions tomorrow and Wed in the Visual Studio connections track. I'll be presenting the following sessions:
- WPF in Windows Forms and vice versa: This talk will cover the interop story for containing WPF controls in Windows Forms applications and Windows Forms controls in WPF applications. Quite a compelling story for migrating incrementally to WPF, but not without its share of pain points.
- Real World .NET 3.0 Smart Client Deployment: This is a modification of my Real World ClickOnce talk, covering the key aspects of ClickOnce deployment but with a slant towards the special considerations introduced by .NET 3.0 for security and WPF deployment models.
- Encapsulate Business Processes in Custom WF Activities: This talk covers how to create custom simple and composite WF activities and all the many things you need to take into consideration to make a robust, reusable activity.
This year the conferences is at the World Center Marriott, a change from the Hyatt Grand Regency of the last few years. Verdict is still out whether this is an improvement...
Tuesday, March 20, 2007
The WPF Book You Can't Live Without - WPF Unleashed
I've been doing a lot of WPF work lately and recently read Adam Nathan's WPF Unleashed to brush up on a few of the more advanced topics that I had not yet spent a lot of time on.
I can't say enough about how fantastic this book is. Never mind that it is extremely well written, easy to read, flows nicely, and yet is very dense in content. The organization is excellent and he wastes no time on fluff but gets right to the meat of what is different about WPF from Windows Forms or ASP.NET right up front.
Then the clincher - the ENTIRE BOOK IS IN COLOR! Code snippets, figures, Tips and FAQ callouts, everything. Naturally you would want some color for something that is all about rich graphics like WPF, but it didn't even occur to me how wonderful it would be to have the whole book in color until I experienced it. Now, it is like my first taste of a color monitor after years of green screens and greyscales - wow. It was a whole different experience and I don't want to go back to those black and white paper thingies. Alas, I think it will be quite some time before all programming books are in color, but it will be a happy day when they are.
A plea to all publishers: Please at least offer a color variant. I'll pay more!! It is worth it!
A word to Adam: Thanks for this great book. You have raised the bar for the rest of us authors.
Tuesday, March 13, 2007
Monday, March 12, 2007
Hands on WPF - dnrTV - Part 1
I recorded a dnrTV with Carl a while back on WPF and it was posted last week. I'll be recording a part 2 this week so keep your eyes out for that. This episode gives a good overview of what programming WPF is like (for now until the tools evolve some more) and what the structure of a WPF application is. Part 2 will dive deeper into data binding, styles and resources, as well as a few other things.
Saturday, February 17, 2007
NOVA / DC Area Code Camp
Wow, is this really my first blog post this year? The year has started off busy busy busy.
But enough about me... this is about you! YOU need to come to the NOVA Code Camp on 14 April! YOU need to volunteer to speak if you have some knowledge you are willing to share with your fellow developers.
I hope to see you there.
Details: http://novacodecamp.org/
Thursday, December 28, 2006
Friday, December 1, 2006
Tuesday, November 21, 2006
ClickOnce Publisher Certificate Renewals and Updating Your Application
A fairly messy little detail of ClickOnce has surfaced that I wanted to get some word out about regarding publisher certificate renewals and how they affect ClickOnce.
ClickOnce only allows you to perform an update to an application if the updated version manifests are signed by the same publisher certificate as was used to originally sign the application.
When ClickOnce was designed, the product team understanding was that certificate issuers such as Verisign and thawte would renew certificates without re-issuing a new certificate (with a new private/public key pair). Unfortunately, that understanding was incorrect. Certificate issuers do in fact issue a whole new cert, just one that has the same CN (Common Name) when they do a renewal.
The result of this is that if you have a ClickOnce application in production and your publisher cert expires, you will no longer be able to issue updates to your application with your new cert. You will have to have users uninstall the previous version and install the new version as a fresh install.
To combat this for the near term, you may want to consider buying a cert that lasts longer than a year.
Microsoft is looking into a fix for this in the Orcas release, but the details of what that fix will look like and how it will affect the update process is yet to be determined.
.NET | ClickOnce  Tuesday, November 21, 2006 9:35:16 PM (GMT Standard Time, UTC+00:00)  |
Friday, November 17, 2006
Contest complete
Congratulations to Dan Kahler for coming up with the correct answer and winning a free seat in the class!
IDesign Advanced .NET Master Class Seat Giveaway
If you want to win a free seat for our Advanced .NET 2.0 Master Class, being held 4-8 Dec 2006 in Reston, VA, be the first one to email me at brian.noyesATidesign.net with the answer to the following question:
What is the name of the class that you use to sign a ClickOnce manifest after making modifications to it and writing it out with the manifest utility APIs?
Race is on!
.NET | ClickOnce  Friday, November 17, 2006 7:16:47 PM (GMT Standard Time, UTC+00:00)  |
Friday, November 10, 2006
DevConnections Vegas Slides and Demos
Another great conference complete. Around 5000 showed up and we had great feedback from the crowd that it was a good show. If you haven't been to connections before, you really should check it out.
I gave three talks this week. You can get the slides and demos for each below.
Real World ClickOnce: Slides Demos Workflow Driven Windows Applications: Slides Demos Implement a Data Layer with the VS 2005 DataSet Designer: Slides Demos
Sunday, November 5, 2006
ClickOnce Publishing from Visual Studio on Windows Vista
If you haven't experienced Windows Vista yet, it is a very cool operating system, but there are a lot of lessons to learn in getting up to speed in working in the new environment.
The biggest thing to get used to if you haven't been running a non-admin account on your XP machine is that there are probably a hundred things or more that you get away with that you don't even know that the reason you get away with it is that you are an admin.
In Vista, even when logged in with an administrator account, you are still not allowed to do administrator things without a privilege elevation through a mechanism called User Access Control (UAC). UAC will seem like a living hell at first because all kinds of things will stop working for you. For example, if you are only getting to some files because you are an admin, and an app such as Quicken tries to run and access those files, you will just get whatever kind of error the app vendor decided to surface for a file I/O error. However, the best way to approach it is to treat it as a learning experience to figure out how to avoid running things as admin unless you really need to (i.e. give your user account permissions to the directories you really need, don't rely on Admin privilege to give you access).
Another example is when publishing with ClickOnce. When you publish from Visual Studio to an http address, VS uses Frontpage Server Extensions (FPE) to create the virtual directory and copy the files to it. First step on Windows Vista is that you need to have IIS 6 Compatibility enabled (it is not on by default, nor is IIS installed by default like XP). Once you do that, IIS 7 knows how to look like a Frontpage Server Extension endpoint. The other thing is that you can only access the web server through FPE if you are accessing as an admin from VS.
Even when logged in as an admin, VS will not be running with admin privilege by default. As a result, when you try to publish a ClickOnce app you will get an obscure error that says that FPE is not installed on the server. Specifically:
"Failed to connect to 'http://localhost/WindowsApplication3/' with the following error: Unable to create the Web 'http://localhost/WindowsApplication3/'. The Web server does not appear to have the FrontPage server extensions installed."
The solution is quite simple: you need to run VS as an admin. To do this, you can right click on the shortcut to VS from the start menu and select Run as Administrator.
If you want to always run VS as admin, do the following:
- Go to devenv.exe in the C:\Program Files\Microsoft Visual Studio 8\Common7\IDE directory.
- Right click and go to properties.
- Select the Compatibility tab.
- Check the box at the bottom that says Run this program as an administrator (see below).

The new security protections of UAC are there for a reason. You could just turn it off and you wouldn't have problems like this in the first place. I'd encourage you not to do that. Use it as a tool to teach you how to get your work done without admin privilege to the extent possible. So in this case I prefer to only run VS as an admin when I need to by doing the right click - Run as Administrator option instead of always enabling it, but you will have to make these productivity vs security decisions for yourself.
.NET | ClickOnce  Sunday, November 5, 2006 7:27:21 PM (GMT Standard Time, UTC+00:00)  |
Friday, November 3, 2006
ClickOnce Deployment Application Identity
One scenario people want to support is to have multiple versions of the same application installed to a single machine/user's account. The guidance I put together for patterns and practices has a walkthrough of setting this up. For example, say you have a version 2.0.0.0 of an application that is your production version, and you publish a new beta version (3.0.0.0) that you want a limited set of users to access, but those same users need to be able to run both production and beta side by side through ClickOnce on their machines (perhaps for feature comparison testing).
The first step is that you will need to have different deployment manifests for the multiple versions you want a single user to run. You direct the user to launch from each URL to the different deployment manifests and they will get a separate installation on their machine... or will they? The answer depends on a hidden aspect of the ClickOnce runtime regarding what the runtime considers a unique identity for an installed application.
If you are not familiar with the things that ClickOnce does under the covers to install an application on a client machine, it downloads and caches the deployment manifest, the application manifest, and all of the application files. Those manifests have to be signed by a publisher certificate that is cryptographically unique. Additionally, the installed application has a product name that gets embedded in the deployment manifest.
You might be tempted, as I was, to think that a unique product name, combined with a separate deployment manifest would be sufficient to make the client machine treat those installs as separate and distinct (such as setting the product names to "MyApp" and "MyApp - Beta"). Unfortunately you would be wrong, as I was.
There is actually a separate piece of information that the ClickOnce runtime uses to distinguish one application from another - the application identity is set by an identity set for the deployment manifest itself. This identity is normally created by Visual Studio when publishing and is set to the deployment manifest name (i.e. WindowsApplication1.application). You do not have control from Visual Studio to set this to anything else. Through the mageui.exe SDK tool, or better yet my Manifest Manager Utility included with the patterns and practices guidance, you can set this application identity to any string that you like to uniquely identify multiple published versions of a single application.
So to address the scenario presented earlier, you can simply set the application identity to MyApp for one version and MyApp-Beta for the other version, and you will be able to side-by-side install those two copies of the app on the same machine.
.NET | ClickOnce  Friday, November 3, 2006 8:30:14 PM (GMT Standard Time, UTC+00:00)  |
Thursday, November 2, 2006
SCSF ClickOnce Guidance Available
I recently put together a bunch of guidance topics for Microsoft Patterns and Practices for doing ClickOnce deployments of CAB-based applications. This guidance and the sample code is now available as a Community Resource Kit and will eventually be incorporated into a future release of SCSF.
The resource kit also includes something a lot of people have been asking for - an example of programming against the manifest APIs in the Microsoft.Build.Tasks.Deployment.ManifestUtilities namespace. I wrote a Manifest Manager Utility as part of that effort and included in the download code that makes common tasks such as updating application files a lot easier. It takes care of signing both manifests at one to make sure they are in sync, updates the deployment manifest reference to the app manifest and other things like that. If you need to go beyond what it does, then you now have sample code available to show you how to work with the APIs.
Another thing included in the kit is an example server side deployment repository provider that allows you to take over the process of serving up manifests and application files on the deployment server so that you could retrieve them from anywhere or even generate some of the files on the fly.
Enjoy!
Get it here!
Monday, October 23, 2006
Monday, October 16, 2006
.NET 3.0 Adoption and the current relative importance of its pieces
We (at IDesign (http://www.idesign.net)) are currently in the middle of a .NET 3.0 Roadshow (http://www.net3roadshow.com) across six cities in the U.S.
In the show, we cover a full day + 1 session of WCF, 2 sessions of WF, 1 session of CardSpace, and 1 session of WPF. I am doing the WF and WPF sessions.
A common question that is coming up is why this weighted mix instead of a more even spread of coverage?
It has nothing to do with the complexity of the topics. WF is equally as complex and capable for what it is designed to address as WCF is for its purposes. WPF is also very complex and capable. CardSpace has a much narrower focus than the others, but has a fair amount of complexity surrounding it as well.
The mix we came up with has a number of reasons behind it, but one of the most important factors was considering how many development organizations should be considering adoption of each technology at this point in time.
WCF is a remote communications platform that is rock solid, easy to use for simple scenarios, yet has a million knobs and dials that you can twiddle to address almost any remote communications needs. My perspective on WCF is that if you are writing any application from this day forward (even though WCF won't release until next month) that needs to make remote calls, you should be using WCF and forget that .NET Remoting, ASP.NET Web Services, and Enterprise Services exist. Obviously that has to be tempered with your ability to get .NET 3.0 deployed to the target platforms. But unless there is an unmovable roadblock to you doing that, it is worth your while to make the switch to WCF as soon as possible. Every application of any significant scale has at least a cross process hop to deal with somewhere in its architecture, and WCF works great for addressing those simple scenarios as well as full enterprise scale SOA apps. So I feel WCF should be adopted by most development organizations as soon as possible.
WF is an extremely capable platform for developing workflow driven processing in your enterprise applications. It is very stable and ready for adoption by those who need it. The only downside to WF is that because of some the capabilities that are built in to WF to address enterprise requirements (persistence, tracking, and scheduling to name a few), I don't think you can really say that simple scenarios are easy to implement with WF. So it takes fairly complex enterprise application requirements to justify the adoption of WF in your application. Additionally, not every application out there really has workflows of any significance (there are a lot of pure CRUD apps still out there). As a result, I think the number of development organizations that should be adopting WF at this time is smaller by at least 1/2 than those who should be looking at WCF.
WPF is a harder one to nail down, and my opinions are likely to incite some flames. I think that there are a lot fewer development organizations that should be bothering with WPF for the near future. The reason mainly has to do with productivity. Even though the runtime bits for WPF will be part of the .NET 3.0 release, the development tools for designing WPF UIs will not. Microsoft is hard at work on a WPF designer for Visual Studio that will hopefully release sometime next year. Alongside that effort is the Expression Suite that includes the Interactive Designer product for allowing designers to put together WPF UIs that they can hand over to developers to complete the hook up of the dynamic behaviors of the application from code. At this point in time and for at least the next 6 months, those products will only be available in a Beta form.
Even with the Visual Studio WPF designer, there is an awful lot missing at this point when compared to the Windows Forms or ASP.NET designers for rapidly designing and implementing UI applications. Even once they release next year, I suspect they will still feel like a v 1.0 designer. Think about how the Windows Forms designer in VS 2002 compares with the VS 2005 designer. Night and day in terms of productivity and producing good maintainable code. Hopefully the gap will not be that large. At the current time, if you want to write WPF apps, you will mostly be banging out XAML markup by hand (thankfully at least with some great intellisense assistance). The current CTP of the Visual Studio Orcas WPF designer does at least work pretty well for visualizing the result of your markup, but it is not really useful for doing a graphical drag/drop layout of your form nor for getting things like data bindings, styles, and resources hooked up.
You also have to consider how bad do you need/want what WPF offers. One of the biggest draws of WPF is that it allows you to write UI applications that are more visually compelling. In short, you could say WPF allows you to create eye-candy that you either couldn't do before or that was orders of magnitude harder to do. What you have to ask yourself is how bad you really need eye candy? If you are building consumer applications, then definitely eye candy is important. The difference between someone buying/using your app instead of your competitors is often a simple matter of whether they look at it, get a glazed look in their eye, and say "Keewwlll....." But if you are building internal enterprise business applications that show and manipulate data, do you really need pulsating 3D bar charts? Maybe, but it is a lot harder to sell that as a "requirement" than "I need my web server to be separated from my application server for security/scalability reasons" (i.e. I need WCF).
Don't get me wrong - I would love to incorporate many WPF features into every Windows app I build from today forward. Using things like styling and subtle opacity animations can make any application look better and more intuitive. Once you have adopted WPF, some of the other features of WPF such as the ability to use Style, Data, and Control Templates is very powerful and will be a welcome new model compared to Windows Forms. But the relative number of apps out there that really need embedded 3D modeling or video I think you can say is considerably less than the number of applications that need to do a cross process, machine, or network hop.
Compounding the problem is the fact that adopting WPF implies that you think you can get .NET 3.0 deployed to all of your client desktop machines to support your application. For an enterprise, that may be true if your organization is savvy about the benefits of adopting new technology and not overly paranoid about the risks of deploying a new version of the .NET Framework. For the open consumer market (yes, the primary ones who would drive you to want to incorporate eye-candy), that is going to be a much tougher nut to crack. For a back end server that you want to run WCF or WF on, having the control to deploy .NET 3.0 to that machine should be a lot easier to satisfy.
So as a result of the current maturity of the tools (equating directly to productivity), the relative importance of the completely new capabilities WPF provides compared to Windows Forms or ASP.NET, and the ability to guarantee that .NET 3.0 is installed on the client machine, I would say that a lot less people should be jumping on WPF for the near term. Once we have a good, near production designer for WPF apps in Visual Studio, my tune will change. Also, for those that really need some aspects of WPF now, by all means go for it. But my primary strategy for most smart client apps at this point would be to build it as a Windows Forms application to address the bulk of your requirements (and complete them in a reasonable timeframe), and then incorporate things like 3D, video, animations, etc. as needed using WPF controls embedded in the Windows application through interop (WPF controls can be hosted in a Windows Forms application and vice versa).
CardSpace's role in the mix is easier to address because it only really addresses one set of requirements: authentication and identity management. It does it well and provides a great new model for identity management that you should definitely be getting familiar with and thinking about how to incorporate it into your applications. CardSpace too faces some adoption challenges since it requires both a service or site that supports CardSpace and a client that has IE 7 or a smart client app designed to work with CardSpace. It definitely warranted coverage in the roadshow and Michele does an awesome session on it. But it definitely did not warrant more than one session compared to overall complexity and capabilities of the technology compared to WCF, WF, and WPF.
These were some of the considerations that drive the mix of sessions we are offering in the roadshow.
I'd be very interested in some comments on other perspectives on WCF, WPF, or WF adoption.
Friday, October 13, 2006
.NET 3.0 Roadshow Slides, Demos, and Links
This week and next my colleagues Juval Lowy and Michele Leroux Bustamante (http://dasblonde.com) and I are conducting a two day seminar on .NET 3.0 development as a roadshow in 6 cities across the country (LA, San Jose, Chicago, DC, New York, and Boston). We have completed LA and San Jose with great feedback from the crowd and are in the middle of the Chicago show.
You can grab the slides and demos for my WF and WPF sessions here: Slides Demos http://www.softinsight.com/downloads/NET30RoadShow/Slides.zip http://www.softinsight.com/downloads/NET30RoadShow/democode.zip
In the WPF talk, I demonstrated several apps others have written that do a good job of displaying some of the awesome graphics capabilities of WPF. Those apps can be found through the links below. I also mentioned a great document for getting up to speed on WPF when you know Windows Forms 2.0 capabilities well. That link is below as well.
Enjoy!
Cine.View: A WPF viewing application that exposes the NetFlix catalog and ordering capabilities created by the thirteen23 company. They also have a great viewer for Flickr. http://www.thirteen23.com/
New York Times Reader: A WPF content application that provides a rich browsing and reading experience for the paper's news content online in a Windows application. http://firstlook.nytimes.com Karen Corby's Woodgrove Finance application: This is a WPF XAML Browser application that provides rich visualization of stock market data in a multi-paned WPF app that runs in the browser. http://scorbs.com/
Keep an eye on http://wpf.netfx3.com for some more upcoming samples that will wow your eyes.
The WPF for Windows Developers document from Mark Boulter and Jessica Fosler can be found on Jessica Fosler's blog: http://blogs.msdn.com/jfoscoding/articles/765135.aspx
Thursday, October 5, 2006
Wednesday, September 6, 2006
Smart Client Deployment with ClickOnce - Final Manuscript Complete!
I'm very pleased to announce that my ClickOnce book is done. I still have to go through the production cycle, which involves reviewing and responding to changes and recommendations by the copy editors. But the content is done, tech reviewed, and ready to go other than that. The cover has been designed and is looking pretty sweet:

It was actually the publisher's idea to incorporate an aircraft on the cover, which I of course loved with my background flying F-14's. It actually makes a lot of sense if you know much about the mission of naval aviation. Our job was to deploy - deploy on the carrier to bring the military might of the US to wherever it was needed, and to deploy weapons on target. ClickOnce is about deploying a different kind of weapon (the smart client app you write) on target (the client desktop). But the metaphor fits in my mind.
The book should be up on Rough Cuts (http://my.safaribooksonline.com/roughcuts) in the very near future in case you want to get your hands on it sooner than when it comes out in print (probably January by the time we get through production).
There is nothing quite like the feeling of finishing a book after many months of having it hanging over your head as that thing you gotta find time for. Now I can tend to the many projects I have sidelined while trying to wrap this book up while maintaining a full consulting load. My wife Robin will be quite glad that I don't have "the book" as an excuse any more. :)
Sunday, September 3, 2006
New IDesign Member - Mark Michaelis
I'm very excited to announce that Mark Michaelis (http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=3) has joined our ranks at IDesign. I've had the pleasure of knowing and working with Mark for several years now through various system design review and early adopter program teams at Microsoft. He is a brilliant guy, has a great book (Essential C# 2.0), speaks at conferences, writes articles, and is a natural fit for what we do at IDesign. I'm sure you will be seeing more and more of his name in the community.
Welcome aboard Mark!
.NET | Community  Sunday, September 3, 2006 3:52:42 PM (GMT Daylight Time, UTC+01:00)  |
Wednesday, August 16, 2006
Understanding Windows Workflow Foundation (WF) and its complexities
I gave a talk at the Greensville Spartanburg Developers Guild last night on Windows Workflow Foundation. The talk covers the basics of WF, including the fact that WF is not basic at all, it has a lot of complexities that have to be mastered to build real applications. There is a lot of power there and it makes sense to use it for workflow oriented enterprise applications, but this is not something you decide to adopt for a couple of conditionals and a loop in your business processing layer.
You can get the slides and demos here: Slides Demos
The more I work with WF, the more comfortable I get with it, but also the more I become convinced that they need a WF-Lite version. There are several key things I highlight in this talk that seem much more complex than they need to be. I understand the reasoning of some of these things, mostly tied to the fact that:
- WF manages workflow scheduling and execution using threads from the thread pool
- WF supports dehydrating your workflow when it is idle, persisting it to a persistence provider (SQL Server supported out of the box), and unloading it from memory
- WF supports logging tracking information to a persistent store to know what workflows/activities are running when and what their state is.
The thing is that not all systems that could benefit from the abstracted design model of WF need these things. But by having these things, it means that certain aspects, particularly communicating with the executing workflow, are much harder than calling from one chunk of code to another in a standard .NET application. If we had a WF-Lite that provided the design time experience (with improvements… see below), but let the app control workflow instantiation and synchronous execution, this technology could apply to even more applications than it will in its current incarnation.
Some of the things that I find people have the hardest time groking are:
1. Presentation of workflow constructs as "Properties". A property is a first class construct of a type in .NET. It has a very precise meaning, as compared to events and methods. In WF, there are a lot of things that are exposed in the designer through the Properties window that are not really properties. They are events or event handler methods that are in your workflow or activities that you are hooking up. Event handlers should show up in the events view to be consistent with other design experiences in VS, and because that is where they belong. Instead, they show up in both the properties view and sometimes in the events view and it makes it confusing as a coder what the heck the designer is creating for you. WF is for developers, so speak the developers lingo dammit.
2. Code Conditions - a bool is just a bool. If you need to hook up an activity that depends on a condition (i.e. IfElse, While, ConditionalActivityGroup, etc.), you should be able to define either a method that returns a bool and point to it, or you should be able to define a bool property and point to it. The model of having to have an event defined that takes a ConditionalEventArgs, hooking up an event handler to that event, and then setting the event argument Result property to true/false just leaves people going "Whahuhhhh????"
3. HandleExternalEvent/CallExternalMethod - The number of things you have to do to conceptually just make a simple method call from the host to the workflow or vice versa is just way too high. I like the fact that the communications are based on interfaces. That part I like from a design perspective – the workflow is sort of a layer unto itself and communicating through an interface is a good way to enforce that separation. However, the number of steps you have to go through to hook up host communication scenarios is just way too high. The calls from the workflow into the host are not too bad, because those just get defined as methods. But the extra steps for the events that provide calls into the workflow just pushes it over the edge.
If you are not familiar with this model, the steps include:
- Define an event argument type to carry parameters (only needed because of the chosen event model - this should change in my opinion) that derives from ExternalDataEventArgs
- Define an interface marked with the ExternalDataExchange attribute
- Define an event on that interface of the type EventHandler<T>, where T is your event argument type
- Hook up the interface and the event to the HandleExternalEvent activity in your workflow that you want to be the call point for the call from the host into the workflow
- Define a class in the host application that implements the interface
- Have a way to fire the event in that class when you want to call into the workflow (a trigger/fire method)
- Register the ExternalDataExchangeService with the runtime when you start it up
- Register an instance of the class that implements the interface with the ExternalDataExchangeService instance that you registered with the runtime
- Finally, trigger the event from the host application at the point where you want to call into the workflow
All of this amounts to what? A simple method call with parameters into the workflow. This is where the attendees jaws usually hit the floor.
Am I wrong here? Isn't this a little more complex than it needs to be for most apps?
Tuesday, August 15, 2006
Thursday, July 27, 2006
Get Up To Speed on .NET 3.0
If you are looking to bootstrap your knowledge on .NET 3.0 (WCF, WF, WPF, and WCS specifically), then a great opportunity is coming to a city near you (well, hopefully reachable from where you are) in October. My colleagues and I from IDesign will be presenting a .NET 3.0 Roadshow in conjunction with CMP media. This event will provide a full day of WCF presented by Juval Lowy and the second day will be split between WF, WPF, and WCF and will be presented by myself and Michele Leroux Bustamante.
You can find more details and registration info here:
http://www.net3roadshow.com/
.NET | Speaking  Thursday, July 27, 2006 5:53:05 PM (GMT Daylight Time, UTC+01:00)  |
Friday, July 21, 2006
Microsoft Principles to Promote Competition
I always cringe whenever I hear about another lawsuit aimed at Microsoft for this or that perceived anti-trust violation or unfair practices. Recent examples include the EU's recent verdict on Microsoft's appeal to the 2004 ruling imposing fines on Microsoft, and Adobe's effort to force Microsoft to remove features from Office 2007 that simply add features that already exist in many other products.
As a developer, I am constantly overwhelmed with the power, capability and productivity that Microsoft puts into developers hands... all of which can be used to develop all kinds of software, including software that might compete with Microsoft's own products. The operating system's open-ness is also both a blessing and a curse. The biggest blight on the ease of use debate between Macs and PCs (highlighted by the recent cute and funny series of commercials by Mac) is really a direct result of the fact that Microsoft is so darned open with the OS - they will let any darn vendor provide software or hardware components for the OS that claim to work fine with Windows, and then when they don't, people blame the OS manufacturer, not the component vendors, yet they fail to see the fact that it is the very openness of the platform that causes the problems. In the next breath, they are cursing Microsoft for trying to squash the competition by running every other company out of business.
The sad fact is that these kinds of lawsuits just hurt the consumer. For those hundreds of millions of us out there who happen to use and like the Windows operating system, we just get less features and capabilities because opponents want to use Microsoft's prominence in the industry as evidence that it must be doing something wrong. How about they create a great product at a competitive price, and that is a hard equation for many companies to measure up to? It also hurts the shareholders and employees of Microsoft (whos numbers are not insignificant) because Microsoft's revenues are burned up in flames in legal costs.
Yesterday Brad Smith, Microsoft General Counsel, gave a talk I wish I could have attended that outlined 12 principles to promote competition. The overview of the talk, the principles, and a vibrant community discussion are going on here: http://news.com.com/Microsoft+vows+to+play+fair/2100-1014_3-6096011.html
I read over this list and it looks to me like things Microsoft has been doing for many years now. Unfortunately it is also being spun as "Microsoft is finally agreeing to play fair", implying that they haven't been doing these things all along.
Whatever the case, I think it is a good thing to have these principles outlined as a manifesto of sorts that people can measure Microsoft and other companies against to try to see if there is any basis for the frequent and invalid claims of unfair practices that get levied against Microsoft. Maybe people can quit spending expensive resources on fighting suits like the EU one and focus on providing what is best for consumers and the economy.
.NET | Community  Friday, July 21, 2006 12:21:08 AM (GMT Daylight Time, UTC+01:00)  |
Friday, July 14, 2006
MSDN Webcast: Implement a Data Access Layer with the Visual Studio 2005 DataSet Designer slides and demos
Here are the slides and demos from last week's webcast. Keep in mind that you will need to add a Modified DateTime column and respective stored procedures to your database to be able to run the code as it was demo'ed in the webcast. The demo code includes my CodeSmith templates for generating those stored procedures and also one for making the coumn modification scripts for you if you want to do it to all the tables in your database that are transactional. There is also a SQL script just for doing the Employees table in Northwind, which was all I used in the demos.
Slides
Demos
Friday, July 7, 2006
Saturday, June 24, 2006
Managing ClickOnce publisher certificate files
I've had several people ask questions surrounding how to get a pfx file to use for ClickOnce manifest signing when you have purchased a real certificate from a provider like Verisign or Comodo (www.instantssl.com - a great, cheaper alternative that has its root issuer already installed as a trusted root certification authority).
Usually when you purchase a certificate, the process involves going to the provider's site, such as instantssl.com, providing your contact information online and entering payment information. The certificate issuer must then verify your identity through some means (corporate DUNS number, business license, bank statement, utility bill, etc.). Once they have done that, they will allow you to download and install your certificate through your browser. They should also provide you with a separate download or generation of a .pvk (private key) file that will contain the private key portion of your certificate. They may or may not provide you a download of a .spc or .cer file that just contains the public key portion of your certificate. If they do not provide a download of the .spc file, you may have to export it from your certificate store after the browser installs it as described later in this post.
Step 1: Download and install pvkimprt.exe If you have a .spc or .cer file and a .pvk file, then you have the pieces you need to create a .pfx file. You will need to download,expand, and install the pfximprt tool, which you can get here:
http://www.microsoft.com/downloads/details.aspx?FamilyID=F9992C94-B129-46BC-B240-414BDFF679A7&displaylang=EN
Generate an install a public/private key pair certificate in your store To generate a pfx file from an spc/cer and pvk file, do the following: 1. Open a command prompt and run pvkimprt, passing the spc and pvk file: C:\>"C:\Program Files\Pvkimprt\pvkimprt.exe" softinsight_comodo.spc softinsight_comodo.pvk 2. You will be prompted for a password for the pvk file as shown in Figure 1. The password is the one you provided when you ordered the certificate or when the pvk file was issued to you.

Figure 1
3. After entering your password and clicking OK, the certificate import wizard will launch as shown in Figure 2.

Figure 2
4. Click Next, and you will be prompted as shown in Figure 3 for selecting the store. Just allow it to automatically select the store (the default) and click Next.

Figure 3
5. You will then just see the summary as shown in Figure 4, click Finish.

Figure 4
6. You should now have a publisher certificate installed into your personal certificate store that contains both the public and private keys for the same certificate. Now you need to export it to a .pfx file that you can back up and use on other machines. Open certmgr by running certmgr.exe from a Visual Studio 2005 command prompt (see Figure 5).

Figure 5
7. Find the certificate you just imported (by publisher name) in the list in the Personal tab (selected by default). Press the Export button. 8. The first step of the export wizard will be presented (see Figure 6). Press Next.

Figure 6
9. The next step asks whether you want to export the private key. If you are generating a pfx file for ClickOnce deployment, the answer here must be yes, which is not selected by default (see Figure 7). Press Next.

Figure 7
10. The next step asks what export file format you want, the default is fine (see Figure 8). Press Next.

Figure 8
11. The next step asks for a password to protect the pfx file that will be output, use a secure password and be careful who you give it to because this is the last line of defense if someone is able to get their hands on your physical pfx file to prevent them from being able to use it. Enter a password twice and click Next (see Figure 9)

Figure 9
12. The next step has you enter the path to the output file. You can press the browse button and navigate to the desired folder and select the file format from the file type drop down, or you can just type in a path (see Figure 10). Press Next.

Figure 10
13. You will see the summary screen, press Finish to generate the file (see Figure 11).

Figure 11
14. You will see a message box showing that the export was successful (see Figure 12).

Figure 12
At this point you now have a pfx file that you can point to with your Visual Studio project Signing tab properties to sign your ClickOnce manifests. You can share that file with other trusted members of your team and they can use it to sign your applications to put them into production.
Just realize that anyone who gets their hands on that file and knows or can guess the password will be able to sign and publish applications that look like they come from you, so you need to treat those files (particularly the pfx and pvk) very carefully.
Monday, June 19, 2006
Another TechEd Complete - Slides and Demos
It was a crazy week at TechEd last week. So crazy, no time to write or consume blogs. I gave two breakout sessions (Real World ClickOnce and Windows Forms: Build Enterprise Ready Forms Applications) and a Birds of Feather session (Windows Workflow Foundation).
You can get the slides and demos from the sessions here:
Real World ClickOnce: Slides Demos
Windows Forms: Build Enterprise Ready Forms Applications: Slides Demos
Friday, June 9, 2006
Monday, May 29, 2006
ClickOnce Trust Model - What Should and Shouldn't You Be Able To Do Through a ClickOnce Install
Julie Lerman has a nice post about creating a desktop icon as part of a ClickOnce install - a fairly common question / request, and very representative of the kinds of "custom" things people would like to be able to do as part of a ClickOnce installation.
There were specific discussions about the option to create a desktop icon in some design reviews in Redmond I took part in several years ago. If I remember correctly, that one was dismissed mostly because it is discouraged to add desktop shortcuts as part of an install, especially without prompting the user to let them choose.
But part of this kind of desire really comes back to understanding the trust model of ClickOnce in general.
The trust issues of ClickOnce are twofold: 1. ClickOnce should not make any modifications to the local machine at install time that could affect other applications or data on the machine. 2. ClickOnce should provide runtime protections to avoid allowing the application to do harm to the local machine.
For #1, this means that you cannot install things to the GAC, add things to the registry, put things in specific places in the file system, etc. Any of those things could affect other apps and users on the machine, which means that administrators are not going to trust low-privilege users to perform ClickOnce installs. As a result, the model will not get adopted in enterprise environments, which is the primary target environment for ClickOnce - to replace those darn intranet web apps that companies create for ease of maintenance with smart client apps that give the user a better experience but are just as easy to maintain because of ClickOnce.
So the bottom line for #1 is that the only forms of customization you have available to you directly through ClickOnce is specifying:
- Whether the app is available offline (meaning you get a Start menu item and an Add or Remove Programs item)
- When updates checks will occur
- What the publisher name is - which sets what the program group in the Start menu is
- What the application name is - which sets the name of the program in the Start menu and Add or Remove Programs
- What the application icon is - through the Visual Studio application settings, and used for the icon in the Start menu item and Add or Remove Programs
There are a number of other assorted options you can set through the Publish tab, but they all really affect how the publication and deployment occurs, but none are in the form of explicit control over what goes where.
For #2 - You specify what runtime permissions the application will have as part of its publish settings (through the Security tab in VS), which end up as a list of required permissions in the application manifest. If those permissions exceed what the application would be granted by Code Access Security at runtime based on the zone of the launch URL (Internet, LocalIntranet, MyComputer, TrustedSites, or RestrictedSites), then the permissions have to be elevated either through user prompting (the default, ClickTwice experience) or through the trusted publishers capability of ClickOnce.
The fact is that you can overcome or workaround any limitations caused by #1 by exploiting #2. If you request full trust for your application, code in your application can do whatever you want it to do when your application first starts up. However, this requires one big assumption - you are also assuming the user who is running your application has sufficient privilege to do whatever it is that your code will try to do. This violates one of the goals of ClickOnce - to provide a deployment mechanism that can be used by low privilege users. So if you write some custom code in your app that tries to create a registry key - your app will have to have Registry permission through ClickOnce, and the user will have to have permission to create a key wherever your app is trying to create it.
As Julie points out, to create the Desktop icon with your own code, the user doesn't need any special permissions because anyone can add a shortcut to their own desktop, but you will need several high trust permissions including unmanaged code execution, which basically means most people will just elevate the application to full trust to get it done. Elevating to full trust is definitely something to avoid if you can.
The recommended way of addressing a lot of scenarios that would require high-privilege custom startup code is to create those things through the Bootstrapper as a prerequisite. A desktop icon is not really a good candidate for that, but pre-deploying something like GAC components is. Making something a prerequisite may allow you to avoid requiring full trust for your application.
However, the dirty little truth about Full Trust is that even though you should always try to avoid jumping all the way to full trust, there are many things that you will likely need to do in any meaningful ClickOnce app that will require you to go to full trust. Examples include:
- Using the ClickOnce API ApplicationDeployment class for just about anything, such as checking if this is the first run of a given version to execute your custom code, or to perform on demand updates.
- Using WCF for remote communications
- Using Windows Workflow in your Windows Forms application
One way to add protections back into your application even if you do have to request full trust for the application as a whole is to have sections of code where you restrict permissions below that level. You can do this through Code Access Security IStackWalk modifiers to Deny certain permissions or PermitOnly certain permissions. You can do this to bracket out a section of code (for example where you call out to some third party component to make sure that they are not doing something like reading/writing from your disk or sending information over the web for data /intelligence collection purposes). The details for doing this are too involved for this post, but I do cover it in my upcoming ClickOnce book and the underpinnings from a CAS perspective are covered well in my colleague Juval Lowy's Programming .NET Components, Second Edition.
Saturday, May 27, 2006
Mid-Atlantic Code Camp - Schedule Up and Volunteers Needed!
The schedule for our upcoming DC area / Mid-Atlantic Region code camp on 10 June in Reston VA is up:
http://www.madcodecamp.com/schedule/codecampmain.htm
The event is being held at the Microsoft Technology Center at:
Microsoft Technology Center 12012 Sunset Hills Rd Reston, VA 20190
You can find directions at:
http://www.microsoft.com/mscorp/info/usaoffices/midatlantic/mtc_reston.mspx
We are currently filled up on registration, but are taking waitlist people to fill in for no-shows.
If you are planning on attending and would be willing to volunteer to help out, please send me a note at brian.noyes(AT)idesign.net. (Change the (AT) to @)
We need volunteers for:
Registration - Help check people in off the registration lists.
Room monitors: All this means is you sit in on a session and make sure that if the speaker needs any help, you can help go and find someone so the speaker doesn't leave the room. You will also prompt the speaker when there is 15 minutes remaining and at completion time so that we can stay on schedule.
Food/drink - Just need a couple of folks to hang out in the food area for the morning break and at lunch to help out if anything is needed.
Friday, May 26, 2006
CAPICOM Build Error on ClickOnce Publishing
I was working with Paul Sheriff of PDSA this week to ClickOnce deploy a reporting tool we use for the Regional Directors program. We ran into a problem where we got the following error when we tried to publish:

The resolution was to obtain the correct version of the CAPICOM.dll, drop it into the \SDK\bin directory where the SignTool.exe lives (C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin with a default VS install), and then register the library with Regsvr32.exe). Since it is a COM library for the CryptoAPI, it can actually live anywhere on your machine once it is registered.
Not sure how this was not there on the machine in question, it normally gets installed and registered when you install VS according to the ClickOnce product team folks.
Wednesday, May 24, 2006
I love the smell of fresh hot bits in the morning...
If you haven't stumbled on the top link on the MSDN homepage in the last 24 hours... WinFX Beta 2 is out. Finally some fresh bits that are synced up between WCF, WPF, and WF.
There is also a Go-Live license associated with all the bits, so you can get the jump on the competition by putting apps into production right away with WinFX capabilities. If you haven't started looking at WinFX capabilities yet, now is definitely the time. One good way to do so is to attend our WCF Master Class. You can find more details at http://www.idesign.net/.
You can get all the download bits for WinFX Beta 2 here: http://msdn.microsoft.com/windowsvista/downloads/products/getthebeta/
Saturday, May 20, 2006
Manually Putting a ClickOnce Application into Production
A common question with respect to ClickOnce is how to take an application that you have published and tested on your local machine or a local development server and move that application into production. The steps involved are not particularly complex, but do involve using some other tools to get it done and are not easy to figure out on your own unless you have a solid understanding of ClickOnce manifests, signing, and how they relate to the launch mechanisms of ClickOnce.
A key pre-requisite for doing this is that the administrator who will be placing the application on the target machine will need to have the publisher certificate that will be used to sign the production application available. Usually in large organizations the developers will not have access to the company's real certificate to do their development anyway, it will be up to the IT Administrator to get that certificate and do the final signing of the applications anyway.
Step 1: Move your application files to the target machine. Assuming you have published your application with Visual Studio to your local machine or another test server in your development environment, the application files are contained in the virtual directory or folder that you specified as the Publish Location within Visual Studio. The deployment manifest, Bootstrapper setup.exe, publish.htm deployment page, and version specific deployment manifests are located in the root folder. For each version you published to that location, there is a subfolder that contains the application manifest and application files for that version. You might do this by zipping up the appropriate files and folders and just giving the zip file to the administrator who will put it into production.
To move the current version into production, you will need to copy the deployment manifest, setup.exe, version-specific manifest and sub-folder for the version you want to publish to the target machine deployment folder. You only need to include the publish.htm file if you intend to use that test page directly to expose the application to end users. But if you are going to put a link to the deployment manifest in some other page or send a link via email, you don't need to include the publish.htm page.
Step 2 (Optional): Make needed changes to application files If you need to change something in the application files, such as changing a setting in the application configuration file or updating some graphics files, you will need to update the application manifest after modifying the application files themselves. So make the modifications needed in your application files.
Step 3: (Only needed if you did step 2): Update the application manifest file list If you made any changes to any application files, you will need to refresh the list of files contained in the application manifest. This is because the manifest contains the hash for each file that provides a unique representation of the contents of the file. If you changed the application file, the hash for that file that is in the application manifest is no longer valid and needs to be updated.
- Open the application manifest (.manifest file in the application files folder for the version you are publishing) with mageui.exe. - Select the Files category in the list on the left side of the window. - Enter the path to the application files folder for the deployment on the right side. - You can press the ellipses (...) button to browse to the folder.

This step does not have to be done on the target machine because only relative paths are stored in the manifest from the location of the manifest, but the manifest and the application files need to be located with the same relative folder path as they will be on the target machine (usually the same directory). - After you have entered the path to the folder, press the Populate button. -You will be prompted with a warning dialog about the fact that the files will be renamed with a .deploy extension. - Click Yes in this dialog.

Step 4: Sign the application manifest If you make any changes to the application files and update the application manifest as described in step 3, or if you just need to re-sign the application manifest with a production certificate that is different than the one that was used in development, then you will need to sign the manifest with Mage. To do so: - Open the .manifest file with mageui.exe if not already open from step 3. - Press the Save button in the toolbar, and you will be presented with the signing dialog shown below.

- Provide the path to the certificate file and the certificate password at the top of the dialog, or select the certificate from your personal certificate store at the bottom of the dialog. - Click OK to sign the manifest with the selected certificate.
Step 5: Update the application manifest reference in the deployment manifest If you performed step 4 and signed with a different certificate than the one used to originally generate the deployment manifest, you now need to update the application reference in the deployment manifest. The application reference is a strong reference to the application manifest from the deployment manifest, including path information as well as the public key token from the digital signature in the application manifest. That signature is generated using the publisher certificate, so if you change the certificate, you have to update the application reference.
To update the application reference, do the following: - Open the deployment manifest (.application file) in mageui.exe - Select Application Reference from the list of categories on the left of the window - Press the Select Manifest... button and navigate to the application manifest (.manifest file) for the version that you are deploying.

Step 6: Update the Deployment Provider If you are moving the application to a different server than the one where you first published the application from Visual Studio, you will need to update the deployment provider URL that is embedded in the deployment manifest. To do so, perform the following steps: - Open the deployment manifest in mageui.exe if it is not already opened from step 5. - Select Deployment Options from the list of categories on the left side of the window. - Change the URL labeled Start Location to reflect the URL users will use to launch the application from the client machine. This setting is saved as the deployment provider in the deployment manifest.

Step 7: Sign the deployment manifest - Click the Save button in the toolbar. - Enter the path and password for the publisher certificate file at the top of the signing dialog, or select the certificate from the list of certificates at the bottom. This should be the same certificate used to sign the application manifest. - Click OK to re-sign the manifest.
At this point, your application should be ready to go from the client.
Slides and Demos from SDC Netherlands
I gave four talks at the Software Developers Conference in Netherlands this week. This is a very fun and interesting conference that is put on by a large user group organization called Software Developers Network, run by Remi Caron and Joop Pecht.
This conference is one of the most enjoyable conferences I get to do anywhere in the world. It is amazing how professional and well run this conference is, especially when you consider that it is being put on by a user group organization and it is better run than many U.S. conferences put on by companies that are supposed to specialize in this kind of event. All of the user group members that run the conference are volunteers, and yet the quality and professionalism that comes out of that is outstanding.
The attendees are hard core, ask great questions, and make the event fun for the speakers as well. For those of you who attended and find your way to this post for the slides and demos - thanks!
You can grab the slides and demos here:
Build Smart Client Data Apps with Windows Forms 2.0: Slides Demos Build Custom Data Bound Objects and Collections: Slides Demos Present Rich Tabular Data with the DataGridView Control: Slides Demos Drive Application Behavior with Application and User Settings: Slides Demos
Saturday, May 13, 2006
DevTeach Slides and Demos
I spoke at DevTeach in Montreal Tue-Thu of this week and had a great time as always. If you haven't checked out this conference, you should plan on signing up next year. Great location, great speakers, very well done conference with lots of hard core sessions.
If you attended one of my sessions and want to get the slides and demos, here you go:
NET371 - Drive App Behavior with Application and User Settings: Slides Demos
NET391 - Custom Bound Objects and Collections: Slides Demos
NET463 - Advanced ClickOnce: Slides Demos
MusicLibrary Database Creation Script: Script
Monday, May 8, 2006
DC Advanced Master Class
I taught a public Advanced .NET Master Class in Reston VA last week. Had a great time, great bunch of students. One of the things that makes teaching the most fun is answering questions, and this was a lively group with the questions. Thanks to all of the students who attended.
A lot of the demos that I give during class are part of the downloads available on our site at http://www.idesign.net. If you want the live demos that I did on the fly, you can download them here:
Live Demos
Saturday, April 15, 2006
Process Identity and Working Directory for Partial Trust ClickOnce Apps
People always ask me "How can you write a whole book on ClickOnce?" because they envision the standard 5 minute demo of what ClickOnce is and does and think that is all there is to it. The fact is there is just a plethora of variations, hidden behaviors, specialized scenarios, and things people want to do with ClickOnce that are far more than 5 minute answers. The book keeps growing the more I get into it.
One of these things that snuck up and bit me recently (unfortunately in a live demo at VS Connections) due to a gap in my knowledge was the way partial trust apps run on the client machine.
First some background on ClickOnce and application files. Any file you add to your project and set the file Build Action property to Content will be added to the Application Files (under the Publish tab in project properties) with a Publish Status of Include, depending on the file type. MDF files (SQL Express), mdb, and XML files will get marked as Data Files instead of Include. Include means the file will be deployed to the application client cache folder under the user profile (C:\Documents and Settings\<username>\Local Settings\Apps\<obfuscated goo>\), and Data File means it will be deployed to a separate data folder associated with that app, also buried in the obfuscated goo under the user profile. The data files are treated differently for updates (beyond the scope of this post) and the folder is accessible through the ApplicationDeployment.DataDirectory property.
If you deploy an app with ClickOnce, and the app manifest requests Full Trust, then when the app runs it simply gets launched by the runtime directly - the app executable is the executable process that runs. It runs from the deployed client cache directory. As a result, with a full trust app, you can access files that you deploy with your app, marked with a Publish Status of Include, with a relative path such as ".\MyImage.jpg". The current working directory when your executable starts is the folder it was launched from, and so everything works out.
Then you decide that you want to be more security concious, and switch your ClickOnce security settings to only require partial trust (lets say LocalIntranet zone). Suddenly your app stops working complaining that it can't find the file.
So what's going on there??
The problem is that the executable process is actually different when you run a ClickOnce app under partial trust. When you configure a ClickOnce deployed app to request less than full trust, the process that actually launches is AppLaunch.exe. This process loads your executable assembly into an AppDomain which it has cranked down the CAS security on to your requested permissions, and your app runs from that appdomain under partial trust. This is similar to what Visual Studio 2005 does to enable partial trust debugging with the <appname>.vshost.exe that is the debug process by default.
So how does that screw up your paths? AppLaunch.exe is running from the .NET directory under C:\WINDOWS\Microsoft.Net\Framework\v2.0.50727\, and so the current working directory for your app loaded into that host process is that folder. Naturally your application files have not been deployed there, so your relative paths for locating the files fail.
OK, so next thought is "there's gotta be an API that I can call to say 'give me my app's deployed directory'". Unfortunately, that thought would be incorrect.
So what's the solution? Simple - don't ever deploy a file to the application directory (Publish Status = Include) that you need to access explicitly through a path (i.e. to load that file as a bitmap, xml file, etc.). If you need to do that, you should mark it as a Data File, and access it by adding the file name to the ApplicationDeployment.DataDirectory path. You can also use Application.UserAppDataPath property, results in the same thing when you are ClickOnce deployed.
Just wish I had known that before doing that demo on the fly in a way I had not done it before in front of a live audience... :)
Tuesday, April 11, 2006
Friday, March 24, 2006
C# Code Snippets Library
If you didn't happen to notice it in your Visual Studio Start page RSS feed, this is very cool. They have put out a very comprehensive Code Snippets library for C#, available here:
http://msdn.microsoft.com/vstudio/downloads/codesnippets/default.aspx
When I teach our Master Class or Advanced Master Class at IDesign, I often get the question of why Visual Basic has a ton of code snippets and why C# only has a couple dozen. I always feel like I am apologizing for the C# team or it is tempting to make a joke at the VB guys's expense and say they need them more, which I really don't believe but is usually got for a laugh (or a few death threats from the VB guys). :)
The fact is we C# guys need them just as bad and should use Code Snippets and other forms of Code Generation such as CodeRush and CodeSmith to the max. Resources like www.gotcodesnippets.com help a lot for not always needing to create one from scratch for every specialized situation you find yourself repeating, but this library gets us even closer with somewhat "out of the box" capabilities.
It includes all kinds of code snippets from collections, to data access to creating data types, cryptography, security, and Windows Forms common needs. These can not only help you avoid writing repetitive code over and over, they give you completed code samples for a lot of situations where you may not have ever written that kind of code before.
Thanks to whoever created this at Microsoft!
Monday, March 13, 2006
Monday, February 27, 2006
What to do when BindingNavigator Raises Exception on AddNew
I got a great question from a reader recently. It's essence reads like this:
If I set up drag and drop data binding to a table that has non-nullable columns, and then press the Add New button twice in the BindingNavigator, I get an unhandled exception on the thread. Since all of the code involved in that call chain is in .NET code and assemblies, how can I handle the exception to keep it from blowing up my app?
If you are not already familiar, to get to this point, you have to create a data bound UI using the Data Sources window, or by hooking up the controls manually. What you end up with after dragging a collection from the Data Sources window onto a form is:
- A DataGridView or Details form of individual controls
- A BindingSource component that is set as the data source of the grid or the individual controls
- A BindingNavigator control that is hooked up to the BindingSource component.
If your data source is a typed data set in the same project, you also get a table adapter instance and data set instance as members on the form, and a Form.Load event handler that fills the appropriate table of the data set so that the app functions without any hand written code. If your data source is coming from a different assembly (an Object data source), then it will be up to you to go retrieve an instance of the collection type and set it as the DataSource property on the BindingSource at runtime to complete the data binding chain.
The way the BindingNavigator gets hooked up, it just points to the BindingSource component and uses the API exposed by a BindingSource to navigate forward and back and to add and delete items from the underlying collection. When you press the Add New button on the BindingNavigator, it calls the AddNew method on BindingSource. The BindingSource passes the call to the underlying collection if it implements the IBindingList interface. Calling AddNew usually also implicitly calls EndEdit on the current item if that item type implements the IEditableObject interface, depending on the collection type's implementation of the AddNew method.
So when dealing with a data table as your collection, you are actually bound to its default DataView. The DataView class implements the IBindingList interface, and the DataRowView class (the items in the collection) implement IEditableObject. When a column in the table is set up so that it does not accept null values, the DataRowView implementation of EndEdit will throw and exception when EndEdit is called if the non-nullable columns have not been provided a value.
The call chain that sets all this up for a standard data set based application is that the BindingNavigator calls into the BindingSource and calls AddNew. This calls into the DataView and adds a new row to the table and starts an editing transaction by calling BeginEdit on the row. When you press the AddNew button a second time, EndEdit is called on the first row you added, which, if you haven't filled in the non-nullable columns, will throw an exception. Since the call chain goes from BindingNavigator to BindingSource to DataView to DataRowView, there is no user code in the call chain where you can logically insert an exception handler.
You could handle the situation in a crude form by having an Application.ThreadException handler, which will catch all unhandled exceptions on the thread. However, this doesn't get called until the stack has unraveled all the way back out to the base of the call stack, so it is a little late to be dealing with the exception in a recoverable way.
A better solution is to inherit from the BindingSource component and provide your own implementation to AddNew. The following implementation (thanks to Steve Lasker and Daniel Herling on the product team in Redmond for coming up with this) shows how:
private class MyBindingSource : BindingSource
{
public MyBindingSource()
: base()
{
}
public override object AddNew()
{
object o = null;
try
{
o = base.AddNew();
}
catch (System.Exception ex)
{
this.OnDataError(
new BindingManagerDataErrorEventArgs(ex));
}
return o;
}
}
With this in place, you can just handle the DataError event on the BindingSource component to do whatever is appropriate based on the exception.
Friday, February 24, 2006
Slides and Demos from Connecting Smart Clients with WCF talk last night - Feb CTP lessons learned
I gave a talk on Connecting Smart Clients at the Microsoft Integration and Connected Systems User Group (MICSUG) last night. I discussed and demoed the basics of using Windows Communication Foundation (WCF) to connect applications, using the newly released Feb CTP.
You can get the slides and demos here: Slides Demos
In jumping through the hoops yesterday to get my demos running on the Feb CTP, there were a number of changes that I had to get used to compared to previous builds.
The biggest is that if you run svcutil against a service that uses wsHttpBinding to generate a proxy, you get a proxy service contract that uses custom message contracts to wrap the parameters and return values from each operation contract. XXXRequest and XXXResponse classes are defined in the proxy file for each operation, along with an XXXBody class that actually contains the raw parameter/DataContract types.
If you program against the service contract interface like so:
IAccountsManager mgrProxy = new AccountsManagerProxy();
You will have to create the XXXRequest message contract types to wrap all the parameters you pass into the methods, and unwrap any return values from the XXXResponse types. However, they also expose a public method on the proxy class directly that encapsulates these details so that you can deal directly with the underlying parameters and return values.
So instead of calling IAccountsManager.GetAllAccounts for example, you will have an easier time calling AccountsManagerProxy.GetAllAccounts.
This is true for wsHttpBinding because of the message level security involved in the default binding. If you use basicHttpBinding, or turn down the security on the wsHttpBinding, then you will get more straightforward service contract interface definitions on the client side proxy.
The resulting proxy and service contract look like the following:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute()]
public interface IAccountsManager
{
// CODEGEN: Generating message contract since message part accountNo requires protection.
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IAccountsManager/CreateAccount", ReplyAction="http://tempuri.org/IAccountsManager/CreateAccountResponse")]
CreateAccountResponse CreateAccount(CreateAccountRequest request);
// CODEGEN: Generating message contract since message part GetAllAccountsResult requires protection.
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IAccountsManager/GetAllAccounts", ReplyAction="http://tempuri.org/IAccountsManager/GetAllAccountsResponse")]
GetAllAccountsResponse GetAllAccounts(GetAllAccountsRequest request);
// CODEGEN: Generating message contract since message part fromAccountNo requires protection.
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IAccountsManager/Transfer", ReplyAction="http://tempuri.org/IAccountsManager/TransferResponse")]
TransferResponse Transfer(TransferRequest request);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface IAccountsManagerChannel : IAccountsManager, System.ServiceModel.IClientChannel
{
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class AccountsManagerProxy : System.ServiceModel.ClientBase<IAccountsManager>, IAccountsManager
{
public AccountsManagerProxy()
{
}
public AccountsManagerProxy(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public AccountsManagerProxy(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public AccountsManagerProxy(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public AccountsManagerProxy(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
CreateAccountResponse IAccountsManager.CreateAccount(CreateAccountRequest request)
{
return base.InnerProxy.CreateAccount(request);
}
public void CreateAccount(int accountNo, string name, decimal initialBalance)
{
CreateAccountRequest inValue = new CreateAccountRequest();
inValue.Body = new CreateAccountRequestBody();
inValue.Body.accountNo = accountNo;
inValue.Body.name = name;
inValue.Body.initialBalance = initialBalance;
CreateAccountResponse retVal = ((IAccountsManager)(this)).CreateAccount(inValue);
}
GetAllAccountsResponse IAccountsManager.GetAllAccounts(GetAllAccountsRequest request)
{
return base.InnerProxy.GetAllAccounts(request);
}
public BankingBusinessLayer.Account[] GetAllAccounts()
{
GetAllAccountsRequest inValue = new GetAllAccountsRequest();
inValue.Body = new GetAllAccountsRequestBody();
GetAllAccountsResponse retVal = ((IAccountsManager)(this)).GetAllAccounts(inValue);
return retVal.Body.GetAllAccountsResult;
}
TransferResponse IAccountsManager.Transfer(TransferRequest request)
{
return base.InnerProxy.Transfer(request);
}
public void Transfer(int fromAccountNo, int toAccountNo, decimal amount)
{
TransferRequest inValue = new TransferRequest();
inValue.Body = new TransferRequestBody();
inValue.Body.fromAccountNo = fromAccountNo;
inValue.Body.toAccountNo = toAccountNo;
inValue.Body.amount = amount;
TransferResponse retVal = ((IAccountsManager)(this)).Transfer(inValue);
}
}
.NET Rocks and DNRtv episodes up
I recorded a DNR and DNRtv last week in New London and they are already up on the site.
You can download/listen to the .NET Rocks! epsidode here: http://www.dotnetrocks.com
And the DNRtv here: http://www.dnrtv.com
In the DNR episode, we talk about data binding, ClickOnce and a few other related topics.
This DNRtv shows how to do some of the data binding stuff in the designer. Keep your eyes out for another episode in a week or so on ClickOnce deployment.
Wednesday, February 22, 2006
Connecting Smart Clients with WCF - MICSUG talk tomorrow nightDebugging SQL Express Apps - Beware VS Copy To Output Directory default
Here is a little trick that has bitten me on more than one occasion, and just bit someone who attended my data binding session in NYC the other night.
Here is the setup to be bitten by the defaults in Visual Studio:
- Add a SQL Express database to your project
- Edit the schema, add some tables, etc.
- Write some code / data binding that uses the database
- Run a debug session adding records or modifying ones you created through the designer.
- Save the changes from your running debug session.
- Shut down the app and run another debug session, and your changes are no longer there.
First instinct at this point is "there is something screwed up with my data binding / data access code". That instinct may be wrong (although we are all good at writing bugs as well).
When VS adds the MDF file to your project, it places it and its related LDF file in the project root folder, and add them to your project in solution explorer. The file properties for the MDF file include Build Action = Content, and Copy To Output Directory = Copy Always.
What is happening is that your changes are being persisted to the copy of the MDF file that was placed in your build output directory (bin\debug) on the first debug run. Then on the second debug run, the unchanged MDF file from the project root folder is copied down into the build output folder, overwriting the one that was there with your changes from the previous run. As a result, it looks like your changes were not persisted when in fact they were (or may have been if your code was correct).
The solution is that whenever you add a SQL Express DB to your VS project, you probably want to change the Copy To Output Directory property for the file to Copy If Newer.
Monday, February 20, 2006
IDesign Newsletter
We have decided to start putting out a periodic newsletter at IDesign with information on the content that we are producing in the form of articles, books, blog posts, and public presentations. There will also be information in there for various events that we are involved in, such as conferences and classes.
If you would like to tap into another great informational resource that just shows up now and then, please subscribe to the IDesign newletter.
.NET | Community  Monday, February 20, 2006 7:44:40 PM (GMT Standard Time, UTC+00:00)  | .NET Rocks! and .NET Rocks! TV Episodes coming up
I went up to New London this week and taped two episodes of DNRtv and one DNR with Carl and Richard. The DNRtv episodes should go up in the next two weeks, one on data binding and one on ClickOnce deployment. The DNR will air on 22 March. Check them out!
Data Binding with Windows Forms 2.0 Slides/Demos from NYC.NET
I gave a talk on data binding in NYC this Thu night. Had a great time. Lively crowd as always, lots of good questions and interaction.
Here are the slides and demos:
Slides Demos
Wednesday, February 8, 2006
Selected as Microsoft Regional Director
Wow. What can I say. Wow. I'm not worthy!
I've been selected for the Microsoft Regional Director program (http://msdn.microsoft.com/isv/rd/) to represent the state of Virginia. Very cool opportunity. More chances for early exposure to new technologies coming out of Microsoft and the opportunity to influence what they become, more opportunities to help the community learn and adopt those technologies, and one of the biggest benefits is being able to collaborate with the other 150 or so RDs, which is quite a brain trust (myself excluded).
I thought being an MVP was a great opportunity, but this makes that pale in comparison!
.NET | Community  Wednesday, February 8, 2006 12:27:28 PM (GMT Standard Time, UTC+00:00)  |
Saturday, February 4, 2006
Thursday, January 19, 2006
Fundamentals of Windows Presentation Foundation talk at ONETUG last night
I gave a presentation on WPF last night in Orlando to ONETUG. Great group, lots of good questions, had a lot of fun.
Here are the slides and demos: Slides Demos
Data Binding with Windows Forms 2.0 Table of Contents
A couple people have suggested that I post the table of contents for my book to my blog since it is not yet available on Amazon.
Here it is:
Foreword xxi
Preface xxiii
Acknowledgments xxxv
About the Author xxxvii
Chapter 1: Building Data-Bound Applications with Windows Forms 1
What Is Data Binding? 2
Your First Data-Bound Windows Forms 2.0 Application 3
Data-Binding Landscape 14
Data Sources 15
Data Objects and Collections 16
DataSets or Not, That Is the Question... 18
Data-Bound Controls 20
Layered Application Architecture 21
What Is a Smart Client? 27
Where Are We? 28
Chapter 2: Working with Typed Data Sets and Table Adapters 31
A Quick Review of DataSets 31
The Quest for Type Safety 34
Typed Data Set Internals 37
Creating Typed Data Sets 41
Creating Typed Data Sets with the Data Set Designer 42
Typed Data Set-Generated Code 49
Introduction to Table Adapters 52
Filling and Updating a Typed Data Set with a Table Adapter 56
Connection Management 58
Adding Transaction Support to a Table Adapter 62
Adding Helper Data Access Methods 66
Basing Table Adapters on Stored Procedures or Views 67
Adding Queries to Table Adapters 69
Creating Typed Data Sets with Command Line Tools 77
Using Typed Data Sets in Your Code 78
Where Are We? 79
Chapter 3: Introducing Data Binding in Windows Forms 81
The 40,000-Foot View of Data Binding 81
Binding Data Collections to a Grid 86
Binding Data Collections to Multi-Valued Controls 88
Binding Data to Individual Controls on a Form 90
Data Paths Within Data Sources 92
Synchronizing Data Between Controls 96
Smarter Data Containment 97
Paging Through Data 99
Master-Details Data Binding 104
Updating Data Sources Through Data Binding 106
Where Are We? 108
Chapter 4: Binding Controls to Data Sources 111
Getting to Know the BindingSource Component 111
Simple Data Binding with Binding Sources 112
Chaining Binding Sources for Master-Details Data Binding 116
Navigating Data Through a Binding Source 121
Manipulating Data Through a Binding Source 122
Using a Binding Source as a Data Storage Container 124
Filling a Binding Source with a Data Reader 126
Sorting, Searching, and Filtering Presented Data with a Binding Source 128
Monitoring the Data with Events 131
Restricting Changes to the Data 133
Underneath the Covers of Data Binding for Complex Types 134
Binding an Image Column to a PictureBox Control 141
Binding a DateTime Column to a DateTimePicker 142
Binding a DateTime Column to a TextBox 144
Binding a Numeric Column to a TextBox 145
Automatic Formatting and Parsing Summary 147
Going Beyond Built-In Type Conversion with Binding Events 148
Handling the Format Event 154
Handling the Parse Event 156
Completing the Editing Process 157
Making the User’s Life Easier with AutoComplete 160
Data Binding Lifecycle 162
Smarter Child-Parent Data Binding 163
Binding to Multiple Copies of Data 165
Updating Parent Data-Bound Controls from Child Data-Bound Controls 168
Synchronizing Many-to-Many Related Collections 172
Where Are We? 176
Chapter 5: Generating Bound Controls with the Visual Studio Designer 177
Working with the Data Sources Window 177
Adding Data Sources to a Project 179
Choosing the Type of Data Source 180
Adding a Database Data Source 181
Adding a Web Service Data Source 185
Adding an Object Data Source 186
Generating Bound Controls from Data Sources 189
Selecting the Bound Control Type 196
Customizing the Bound Control Types 196
Binding Existing Controls to Data Sources 199
Behind the Scenes: Designer Code and Data Sources Files 202
Other Designer Data-Binding Code Generation 205
Setting Control Data Binding Through the Properties Window 206
Generating Data Bindings with Smart Tags 210
Generating Master-Details Data-Bound Controls with the Designer 214
Where Are We? 216
Chapter 6: Presenting Data with the DataGridView Control 217
DataGridView Overview 218
Basic Data Binding with the DataGridView 219
Controlling Modifications to Data in the Grid 221
Programmatic DataGridView Construction 222
Custom Column Content with Unbound Columns 226
Displaying Computed Data in Virtual Mode 233
Using the Built-In Column Types 241
Built-In Header Cells 255
Handling Grid Data Edits 256
Automatic Column Sizing 259
Column and Row Freezing 262
Using the Designer to Define Grids 263
Column Reordering 266
Defining Custom Column and Cell Types 269
Utilizing Cell-Oriented Grid Features 277
Formatting with Styles 281
Where Are We? 284
Chapter 7: Understanding Data-Binding Interfaces 285
What Does Data Binding Have to Do with Interfaces? 286
The IEnumerable and IEnumerator Interfaces: Supporting Iteration Through Collections 289
The ICollection Interface: Controlling Access to a Collection 295
The IList Interface: Enabling Data Binding 298
The IListSource Interface: Exposing Collections of Collections 303
Property Descriptors: Allowing Dynamic Data Item Information Discovery 305
The ITypedList Interface: Exposing Data-Binding Properties 307
The IBindingList Interface: Providing Rich Binding Support 310
The IBindingListView Interface: Supporting Advanced Sorting and Filtering 323
The ICancelAddNew Interface: Supporting Transactional Inserts in a Collection 325
The IRaiseItemChangedEvents Interface: Providing Item Modification Notifications on Collections 327
The IEditableObject Interface: Supporting Transactional Item Modifications 328
The INotifyPropertyChanged Interface: Publishing Item Change Notifications 329
The ICustomTypeDescriptor Interface: Exposing Custom Type Information 332
The ISupportInitialize Interface: Supporting Designer Initialization 334
The IDataErrorInfo Interface: Providing Error Information 330
The ISupportInitializeNotification Interface: Supporting Interdependent Component Initialization 337
The ICurrencyManagerProvider Interface: Exposing a Data Container’s CurrencyManager 341
Where Are We? 341
Chapter 8: Implementing Custom Data-Bound Controls 343
Extending Framework Data-Bound Controls 344
Creating a Grouped Column DataGridView 345
Using Custom Controls 350
The User Control Test Container 352
Developing Data-Bound Container Controls 353
Building a Filtered Grid Control 354
Adding Data-Binding Capability to a Custom Control 357
Supporting Designer Initialization of Data Binding 359
Specifying Binding Properties on a Control 360
Supporting Delayed Initialization with ISupportInitialize 362
Dynamically Determining the Properties of a Data Source 367
Autocompleting Input in a TextBox Control 371
Autosizing Columns in the Grid 375
Winding Up the Filtered Grid Example 376
Building a Custom Data-Bound Control from Scratch 379
Building a Data-Bound Charting Control for Decision Support 379
Coding a Data-Bound Custom Control 384
Adding Editing Support to a Custom Data Bound Control 391
Where Are We? 397
Chapter 9: Implementing Custom Data-Bound Business Objects and Collections 399
Defining and Working with Data-Bound Business Objects 400
Defining and Working with Data-Bound Business Object Collections 405
.NET Framework Generic Collection Classes 406
The CustomBusinessObjects Example 408
Setting the Textual Data-Binding Behavior of Custom Objects 415
Supporting Transacted Object Editing with IEditableObject 416
Supporting Object Edit Notifications with Property Change Events 420
Supporting Object Edit Notifications with INotifyPropertyChanged 423
Using BindingList<T> to Create Rich Object Collections 424
Creating a Custom Collection Type Based on BindingList<T> 426
Managing Transacted Additions to a Collection 439
Raising Item Changed Events 441
Adding IBindingListView Functionality 443
Binding to Business Objects Through the Data Sources Window 453
Where Are We? 455
Chapter 10: Validating Data Input and Handling Errors 457
Windows Forms Validation 458
Handling Validation Events 459
DataGridView Validation Events 462
Validation Up the Control Hierarchy 463
Displaying Validation Errors with the ErrorProvider Control 464
DataGridView Error Displays 467
DataGridView DataError Event 468
Controlling Validation Behavior with the AutoValidate Property 471
Validation down the Control Hierarchy 472
Extended Validation Controls 474
Capturing Data Errors on Data Sets 475
Providing Error Information from Custom Objects with IDataErrorInfo 479
Data Concurrency Resolution 483
Where Are We? 484
Appendix A: Binding to Data in ASP.NET 487
ASP.NET Page Processing Basics 489
Data Binding in ASP.NET 1.X 490
Data-Binding Overview in ASP.NET 2.0 498
Data Sources 499
Data-Binding Expressions 508
GridView Control 509
DetailsView Control 512
FormView Control 514
Master-Details Binding 515
Hierarchical Binding 518
Where Are We? 519
Appendix B: Binding Data in WinFx Applications 521
WinFx UI Programming and Capabilities Overview 522
Writing a Simple WinFx Application 525
WinFx Data Binding 101 532
Data Contexts and Data Sources 536
What About XAML? 537
Binding a Collection to a Grid with Templates 541
Control Styling in WinFx 543
Where Are We? 545
Appendix C: Programming Windows Forms Applications 547
Your First Windows Forms Data Application 548
Creating Windows Forms Applications with Visual Studio 554
Windows Forms Designer-Generated Code (New in 2.0) 563
A Brief Tour of the Windows Forms Architecture 567
The Dawn of .NET Execution—The Main Method 570
Handling Control Events 574
Displaying Other Forms 576
Containing Forms Within a Parent Form 577
Common Data Display Controls 578
Creating a Custom User Control 586
Laying Out Controls on a Form 589
Setting Tab Order 596
Command and Control of Your Windows Forms Applications (New in 2.0) 598
Where Are We? 600
Appendix D: Accessing Data with ADO.NET 601
Relational Data Access 603
The Ubiquitous DataSet 607
Loading Data Sets from a File 609
Creating a Data Set Programmatically 611
Loading Data Sets from a Database 613
Loading a DataTable with a DataReader 619
Master-Details DataSets 621
Retrieving Data with Stored Procedures 623
Updating the Database Using Data Sets 624
Handling Concurrency 628
Updating with Data Sets and Stored Procedures 632
Searching Data Sets 637
Merging Data from Multiple Data Sets 639
Working with Data Views 641
Working with Transactions 643
Scoping Transactions with System.Transactions 647
Client-Side Transactions 650
Data Set and Data Adapter Events 651
Reading Data into Business Objects 654
XML Data Access 658
Working with the XmlDataDocument Class 659
Working with the XPathDocument Class 663
Loading Data into an XPathDocument 664
Querying XML Data 665
Navigating an XML Document 667
Where Are We? 670
Index 671
Wednesday, January 18, 2006
Data Binding with Windows Forms 2.0 Talk in Sarasota last night
I gave a talk on data binding at the Sarasota FL .NEt Users Group last night. Had a great time, and it was especially fun to present this topic this time since it was the first time presenting on data binding since my book came out. Gave away a couple copies. It was also great to go have some beers with the group members afterwards, including fellow MVPs Stan Schultes and David Hayden.
You can grab the slides and demos here: Slides Demos
Data Binding with Windows Forms 2.0 is out!
It was a very cool feeling to have a box of my books delivered to me on Friday. After starting way too early on it and rewriting many of the chapters multiple times as the capabilities evolved in Visual Studio 2005 and .NET 2.0, it felt very good to finish the writing a couple months ago. But having the finished product show up on my doorstep was very cool.
So stop reading this and go buy one dammit! :)
Thursday, January 12, 2006
VS 2005 DC Launch Event
I co-presented the Smart Client session at the DC Launch event yesterday at the Washington Convention Center with Marc Schweigert, a Microsoft Developer Evangelist for the Federal Sector. We covered a lot of good material on Windows Forms 2.0 capabilities including data binding and ClickOnce, two topics close to my heart since I have written/am writing books on them. I also spent most of the day in the Ask the Experts booth along with other local DC area experts like Sahil Malik, Randy Hayes, G. Andrew Duthie, Darrell Norton, Jonathan Cogley and Vishwas Lele. Besides being a great opportunity to catch up with all these guys and exchange ideas, it was a great day talking to developers from the area and seeing how much enthusiasm there is around the availability of VS 2005 and .NET 2.0. Most of the people there had spent little to no time looking at the new stuff, so there was the usual "wow!" reaction when they saw all the great features and capabilities that are now available to them.
I think we ended up with over 2000 attendees at the event, with about a thousand or so sticking around to the bitter end for our session, which was last up at 4:30-5:45.
The folks at Microsoft that put together the event (Darryl Schaffer in particular) did a great job organizing and running the event.
Thursday, January 5, 2006
Awarded MVP for another year! Visual Developer - Solution Architect
Looks like I get to hold onto the MVP title for another year. WooHoo!
Being an MVP has a lot of great benefits, but you need to contribute a lot of time to the community to earn the title. In case people are wondering the kinds of things you can do to qualify, I gave about 35 talks at major conferences in the last year, 14 user group talks, 3 webcasts, wrote a book (Data Binding with Windows Forms 2.0), published about a half dozen articles in various publications, helped run the Captial Area .NET User Group, and participated in 6 Microsoft partner events (SDRs, readiness events, etc.). This is all extra-curricular activity that does not directly earn me any significant money. On top of that I had to continue to earn a living as an architect and trainer with IDesign, which is a lot of fun in itself. Sounds exhausting, but I gotta say I feel pretty lucky to have found something that I love to do so much.
This year I have been moved to the Visual Developer - Solution Architect category instead of ASP.NET because that aligns more with where my primary focus is these days. I'm all about smart clients, but they don't have a category for that yet. I still can hold my own with ASP.NET, but just don't spend as much of my time in that space as with architecture and smart client technologies anymore.
Cool, cool, cool. I feel privileged to count myself part of a very talented community of Microsoft recognized experts!
Data Binding with Windows Forms 2.0 Sample Code Posted
I posted all the sample code for my book Data Binding with Windows Forms 2.0 on the book Web site at http://www.softinsight.com/databindingbook. The samples are available in both C# and VB, even though all the code in the book is in C#. The book should be hitting the shelves very soon and is already selling well on Amazon.
I also posted instructions for running the samples if you do not have a non-default instance of SQL Server or don't have Northwind on your machine yet, also how to run the samples with SQL Server 2005 Express, Visual C# 2005 Express and Visual Basic 2005 Express.
Happy Data Binding!
Thursday, December 1, 2005
Adding a Drop-Down List (ComboBox) Column of Lookup Values in a DataGridView
A common requirement and question that is very easy to solve with the DataGrid is the need to have a column or columns in a grid that contain a drop down list of lookup values from a related table. For example, in Northwind, we have the Products table with a foreign key column SupplierID that relates the to Suppliers table. The values in the Suppliers table could be treated as a list of lookup values for editing the supplier associated with a product:

When a supplier is selected from the drop down list, it should set the SupplierID column value for that row in the products table. This is very easy to achieve through the Windows Forms designer and the smart tag for a DataGridView control.
Do the following to try it out:
1. Create a Windows Forms Project. 2. Add a data source to a data set that contains Products and Suppliers tables from the Northwind database. This could be any kind of Data Source (Database, Object, Web service), but for simplicity for trying out the designer, just use a database one which adds the typed data set into the Windows Forms project. Products is the table of data we will display in the grid, and Suppliers is the lookup table related through a foreign key column in the Products table that we want to display as a combo box of selectable values in the grid. 3. Drag and drop Products from the Data Sources window onto the form. This will generate the grid, a data set instance, a table adapter to fill it, a BindingSource component hooked up to the data set and the Products table within it, a grid hooked up to the products binding source, and a binding navigator hooked up to the binding source. 4. Click on the grid smart tag (little triangle on upper right border of control). 5. Select Dock in Parent Container. 6. Select Edit Columns. 7. Select the SupplierID column in the list on the left. 8. Select the ColumnType property and set it to DataGridViewComboBoxColumn. 9. Select the DataSource property and navigate down through the data source tree through Other Data Sources > Project Data Sources > NorthwindDataSet > Suppliers table.
 10. Select the DisplayMember property and select CompanyName. 11. Select the ValueMember property and select SupplierID. 12. Click OK to close the Edit Columns dialog. 13. Run the app and observe that you get the drop down list of suppliers. Selecting a supplier actually changes the SupplierID column value for that row in the products table to the appropriate foreign key value.
You can download a completed sample that was generated with these steps here.
Wednesday, November 30, 2005
Launching unmanaged applications with ClickOnce
The question came up from several attendees at my MSDN Webcast on ClickOnce yesterday:
"Can I launch a XXX application using ClickOnce?" (fill in XXX with VB6, MFC, etc. - non-.NET applications)
The answer is yes, you will just have to employ a little trick.
What you need is a simple little launcher application that IS a Windows .NET application. So do the following:
- Create a new Windows Application project with VS 2005.
- Delete the Form1 from the project.
- Add the unmanaged EXE and any supporting files to the VS 2005 project, which makes them part of this application from a ClickOnce perspective. As a result, they will get deployed with this application to its cache folder and can be executed by this launcher app.
- Edit the Program.cs file Main method and delete the current method body (which launches the application and the form) and replace it with code to launch the unmanaged executable. This just requires a single line of code: Process.Start("MyUnamangedApp.exe");
Note: You will need to give the launcher app full trust in the ClickOnce security settings.
Note2: If the unmanaged app relies on ActiveX or COM objects, those need to be added to the project as well, and you will need to add a reference to the COM DLL's to the project to get their reg-free COM information added to the manifest. See this article for more details.
You can download a sample implementation here.
Demos from ClickOnce MSDN Webcast
For those who attended or are interested, here are the demos from my MSDN Webcast on ClickOnce yesterday.
You can find the webcast link for on-demand viewing here.
For the demo that went awry demonstrating on-demand updates, the little mistake I made was that I said that if you turn off automatic updates (Check for updates option at top of Updates dialog), then you need to put in an Update location, which is true. But what I was doing was fully qualifying the path to the deployment manifest, which is incorrect. What you need to put is just the URL to the root folder where the deployment manifest resides. VS will automatically append the deployment manifest file name. So when I was putting in:
http://localhost/ClickOnceOnDemand/ClickOnceOnDemand.application
I should have just been putting
http://localhost/ClickOnceOnDemand/
Another little tidbit I didn't mention is that you will need Full Trust for on-demand updates, which is unfortunate because it means the app has to request full trust even though it may not be doing anything privileged beyond on-demand updates.
Tuesday, November 29, 2005
WCF Config file intellisense... why hath thou forsake me?
In previous builds of WCF (Indigo), you had to have a particular namespace included in your config file. Specifically, instead of the default root element of:
<configuration> <!-- The rest of your config settings --> </configuration>
You needed to have:
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <!-- The rest of your config settings --> </configuration>
By doing that in previous builds, you got intellisense for the schema elements and attributes of the <system.serviceModel> element, letting you discover the right entries to get features like transactions, security, bindings and so on correctly configured.
When I installed the Nov CTP, I was immediately lost because my intellisense seemed to have gone away. If you add a WinFx Service from the Web Site templates, the web.config still has the namespace shown in the second config snippet above. But the trick is that it is no longer needed, and in fact confuses VS on what schema elements to expose through intellisense. The system.serviceModel schema elements are now merged with the C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas\DotNetConfig.xsd schema as part of the VS extenstions install, so they are there by default now in the config file intellisense.
Thanks to my colleague Juval Lowy for discovering this fact and giving me back my intellicrack!
DataGridView Webcast demos
Here are the demos from my MSDN Webcast today on the DataGridView control.
You can find the sample DataGridView chapter for my book here.
You can view the webcast on demand through the links here.
Thursday, November 24, 2005
Slides and demos from Boulder .NET
I gave a talk on connecting smart clients with WCF on Tuesday at Boulder .NET. Had a good turnout desipte the proximity to the holiday and had a good time.
The talk covered the fundamentals of connecting applications with WCF since most of the people there had never seen anything on WCF. Then I moved into some of the specific client concerns when using WCF, similar to my talk at VSConnections.
You can get the slides and demos here: Slides Demos
Sunday, November 20, 2005
Interface-based Programming example employing the Factory pattern
When I demonstrate the use of interface-based programming in a class, I always give a demo of using interface-based programming combined with a factory pattern to add dynamic behaviors to an application. This is basically a scaled down version of what the provider model in ASP.NET 2.0 and the Enterprise Library do to allow you to externally configure components that will be called by the framework at runtime. ASP.NET actually uses abstract base classes instead of interfaces because they also provide some shared implementation, but the concepts are basically the same.
I use a simple little example of a client that defines an IDog interface (in a separate interface only assembly that it can share with component providers) that specifies the contract that providers are expected to implement. I then show how to build components separately that the client has no specific type information about, and load and invoke the behavior defined in those components dynamically through a factory and based on the interface definition that is the contract for how those components expose their behavior and some configuration file entries that the factory can use to load and instantiate the types. The client is able to do this without requiring any code modifications to accept new components, and can even have new behaviors added at runtime without needing to restart the application.
I have repacked the demo I normally give in class to:
Make it a little cleaner
Separate out the factory into a generic factory in a separate assembly that could be reused for any project
Use the new Settings features in the .NET 2.0 framework to enter the type information into a configuration file instead of using a separate XML file like I used to.
The factory method looks like the following:
public static T[] ConstructType<T>() where T : class
{
// Refresh the config cache in case the config file has been edited at runtime
Settings.Default.Reload();
// Load the collection of components from the string collection in config
StringCollection componentTypeInfoColl = Settings.Default.Components;
// Create a list to add the components to as they are created
List<T> components = new List<T>();
// Loop through the config strings trying to create instances of the appropriate type
foreach (string componentTypeInfo in componentTypeInfoColl)
{
try
{
// Config entries should be in the form:
// Fully.Qualified.TypeName, AssemblyName
// Split into its two parts
string[] typeInfo = componentTypeInfo.Split(',');
// Dynamic load the assembly
Assembly assem = Assembly.Load(typeInfo[1].Trim());
// Dynamic instance creation
T instance = assem.CreateInstance(typeInfo[0].Trim()) as T;
if (instance != null)
{
components.Add(instance);
}
}
catch { } // Just ignore invalid types
}
return components.ToArray();
}
So the only things you need to know to use this as a factory for other purposes than this demo is that it expects the type information to be entered in the client configuration file with an application settings section like the following:
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="DynamicFactoryLibrary.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<DynamicFactoryLibrary.Properties.Settings>
<setting name="Components" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>Animals.Dog, Animals</string>
<!--
<string>Animals.GermanShepherd, Animals</string>
<string>Animals2.Shitzu, Animals2</string>
-->
</ArrayOfString>
</value>
</setting>
</DynamicFactoryLibrary.Properties.Settings>
</applicationSettings>
</configuration>
I’m just using a StringCollection as the type for the component type collection, so each component that you want to add to the collection should be added to the section in the form:
<string>Animals.Dog, Animals</string>
You can see a couple of additional components commented out for dynamically adding them into the application (even while it is running). The type information uses a standard convention for specifying type information through a config file: specifically the fully qualified type name of the type, followed by a comma, followed by an Assembly name to load it from.
You can grab the whole sample here.
To demonstrate the example in action:
- First build the InterfaceBasedProgramming solution, which builds the interface contract assembly, the factory library, and the client application. The default client config file has all of the type information for available components commented out.
- Open the build output folder of the client (InterfaceBasedClient\bin\debug) and run the client by double clicking on InterfaceBasedClient.exe.
- Push the button and observe that you get nothing because no types have been provided or plugged in though the config file yet. Leave the client running.
- Next open the Animals solution, build it, and copy the build output (Animals.dll) from the bin\Debug folder into the client’s bin\Debug folder.
- Edit the InterfaceBasedClient.exe.config file through an editor, and uncomment the Dog type information as shown in the snippet of config file above, save the file.
- Hit the button in the client again, you should see a standard Dog Bark (through a message box).
- Edit the config file again, uncommenting the type information for a GermanShepherd (which is also defined in the Animals assembly), and save.
- Push the button again and you will see that type is dynamically used from the already loaded assembly.
- Go open the Animals2 solution and build it.
- Copy the Animals2.dll from its bin\Debug folder into the bin\Debug folder for the client.
- Edit the config file for the client again to uncomment the type information for the Shitzu type, and save.
- Click the button in the client again and you should see all three types of dogs bark.
Friday, November 11, 2005
WCF Talks: Event Driven Applications and Connecting Smart Clients
I gave two WCF (Indigo) talks at DevConnections today:
Build Event Driven Applications with Indigo: Slides Demos
Connecting Smart Client Applications with Indigo: Slides Demos
In the Event Driven Applications session I cover creating list based subscription services with direct callback services in the clients, using duplex channels to set up callbacks, and a Pub-Sub implementation that gives loosely coupled events that I will have more information on here in the near future.
In the smart client session, I covered client concerns with respect to channel selection, asynchronous calls, sessions, transactions, callbacks, security, and peer-to-peer.
Good time!
Secure ClickOnce Demployment Talk at DevConnections yesterday
My second session of the day yesterday at DevConnections was on ClickOnce deployments, and specifically the various security protections and options that ClickOnce offers for preventing unauthorized applications from being able to run through a ClickOnce launch.
You can grab the slides and demos here: Slides Demos
Some of the key takeaways from this session were the following:
- ClickOnce provides a simple, powerful, and easy to use mechanism for deploying smart client applications with minimal maintenance effort and IT Admin involvement
- ClickOnce provides runtime security protections through the Code Access Security (CAS) infrastructure of .NET to prevent applications launched from ClickOnce from being granted permissions to perform any operations or access any resources that the application was not specifically allowed to do.
- ClickOnce app default permissions are determined by the launch URL and how it maps to built-in CAS location-based code groups (MyComputer, LocalIntranet, Internet, TrustedSites, UntrustedSites).
- If the application manifest requests permissions greater than those that would be granted based on the CAS location-based code groups, permission elevation needs to occur.
- By default, permissions can be elevated in one of two ways: user prompting or trusted publishers.
- If an application is launched through a link to a deployment manifest that is signed by a publisher certificate that is not in the Trusted Publishers certificate store on the client machine, the user will be prompted by default and can accept or reject the application. If they accept it, the permissions for that application will be elevated to whatever permissions the application manifest has requested.
- If an application is launched that was signed with a publisher certificate that is in the client machine's Trusted Publishers certificate store, then no user prompting will occur and the application permissions will be automatically elevated to whatever the application manifest requests because it is coming from a trusted source identified implicitly by IT admin when they installed the publisher certificate in the Trusted Publishers store.
If you want to prevent the user from ever being prompted and only allow applications from trusted publishers to be launched through ClickOnce (a good idea in an enterprise environment), then you should create the registry key discussed in the slides from the session and set the string values to Disabled for all the zones.
Wednesday, November 9, 2005
Build Custom Data Bound Business Objects and Collections Talk at DevConnections this morning
I just got finished doing my first talk here at DevConnections in Vegas and I think it went pretty well. Great crowd, good questions, fun topic.
You can grab the slides and demos here: Slides Demos
The talk highlighted how to define custom objects and collections to make them suitable for data binding, mostly for Windows Forms, but some of it is applicable to ASP.NET as well.
The key takeaways from the talk are:
- Implement INotifyPropertyChanged on any business entitity type you define that you expect to use in data binding scenarios. This interface defines a contract for the objects to raise PropertyChanged events whenever a property is set on the object. It allows containing collections or bound controls to be notified when the contents of the data object change, which helps with keeping controls synchronized in a form.
- Use BindingList<T> to create strongly typed collections of objects that support rich data binding. It provides full implementation of IList, ICollection, IEnumerable and their generic strongly typed counterparts for whatever type parameter you provide, and it provides a partial implementation of the IBindingList interface. The part that it implements is firing ListChanged events when items are added or removed from the collection. It also looks at the objects type that you provide as a type parameter, and if it implements INotifyPropertyChanged, the collection will subscribe to the PropertyChanged event on each object and raise ListChanged events with a change type of PropertyChanged whenever the contents of an object in the collection change. These features make BindingList<T> collections work seamlessly with data binding to multiple controls and keeps the controls all in sync.
- Use my BindingListView<T> class (in the demos and in my book) to get a generic container that supports sorting (both IBindingList based single property sorts and IBindingListView multi-property sorts), searching, and filtering.
If you were there at the end and saw the on-the-fly demo where I didn't see the saving behavior that I thought I had just implemented, I tracked down the problem. the changes were actually being saved. It was just the way I hooked up the data binding I wasn't seeing those changes.
In the demo, I used the data sources window to generate a Details view (control collection) bound to a collection of Album data. I changed one of the controls in the collection which was bound to a GenreID property on the Album objects to a ComboBox. I then used the Data Sources window to add data binidng to a Genre object collection to populate the list of Genres in the combo box. This sets up the ComboBox to have its contents determined by the Genre collection, but its SelectedValue property is bound to the GenreID property on the current item in the Album collection - generally exactly what you want to be able to edit a property on one object collection item through a lookup list of values in another collection of objects. The problem was that after I selected a new value in the combo box and saved the changes, then restarted the app, I wasn't seeing the modified value set for the Album I was viewing in the other controls.
It turns out the problem was just the order that I did the initial binding of the control collection and the combobox BindingSources. In the form load I had added the following two lines of code to bind the control collection and the combo box binding sources:
albumBindingSource.DataSource = Album.GetAlbums(); genreBindingSource.DataSource = Genre.GetGenres();
The problem is that when you set the DataSource, that is when it intializes the bound controls. So I was initializing the data bindings for all of the controls based on the album data, then intializing the combo box of Genres with a new set of data. That set the SelectedIndex of the ComboBox back to zero, so I wasn't seeing the actual value of the Genre for the current Album, I was just seeing the first Genre value in the Genre collection. The fix is simply to do the initial binding in the reverse order:
genreBindingSource.DataSource = Genre.GetGenres(); albumBindingSource.DataSource = Album.GetAlbums();
Then it works as expected.
Some resources I mentioned in the talk, as well as some additional ones I gave related to after-session questions:
My Book: Data Binding in Windows Forms 2.0, Addison Wesley, January 2006 http://www.amazon.com/exec/obidos/ASIN/032126892X/qid%3D1124482085/sr%3D11-1/ref%3Dsr%5F11%5F1/102-3039504-6850510 Rocky Lhotka binding refresh problem post: http://www.lhotka.net/WeBlog/PermaLink.aspx?guid=d8306469-7e76-4734-9811-777498808b85 Rocky Lhotka article on binding to business objects: Windows Forms Object Data Binding in .NET 2.0, 15seconds.com, http://www.15seconds.com/issue/040614.htm My recent article on The Server Side .NET: Build a Data Access Layer with the Visual Studio DataSet Designer, The Server Side .NET, Oct 2005, http://www.theserverside.net/articles/showarticle.tss?id=DataSetDesigner My recent article in CoDe magazine: Tackle Complex Data Binding in Windows Forms 2.0, CoDe Magazine, July/Aug 2005, http://www.code-magazine.com/Article.aspx?quickid=0507051
Enjoy!
ClickOnce user privilege requirements discussion
Great post by my colleague Michele from IDesign following a discussion we had on ClickOnce permissions and what users are allowed to do. Check it out!
Tuesday, November 8, 2005
Las Vegas Bound - Impressions of WCF
I'm catching a flight early tomorrow morning to Vegas for VS Connections and am really looking forward to it. VS Connections in particular, and DevConnections in general (the overall conference event) is well run, in great locations, and always has a lot of great content that I can benefit from as well.
I've been spending most of my recent prep time fine tuning the demos for my two WCF sessions, Build Event Driven Applications with Indigo and Connecting Smart Client Applications with Indigo. The more I work with Windows Communications Foundation (aka "Indigo"), I am struck by a number of things:
- I am impressed by how capable Indigo is.
- I am awed by how elegant and simple solutions are to complex aspects like security, transactions, queuing, callbacks, and so on.
- I am dumbfounded by how hard it is to figure out how to get to those elegant and simple solutions.
The last bullet is not really a criticism of what they have come up with, it is just the nature of the beast. I would draw on an analogy from my flying days to explain why this is so. Imagine the cockpit of a WW I fighter aircraft. You probably have half a dozen or less simple dials and gauges, and a stick and throttle. Imagine trying to use that set of controls on an aircraft that can fly at high subsonic speeds at high altitude carrying hundreds of passengers for 12 hour transoceanic flights. Not going to work too well. This is basically where you were at with past technologies to build complex, distributed, heterogenous, connected enterprise systems. It could be done, but the end result was not going to be pretty and it was going to take you a long time to get there.
Now with WCF, it is more like climbing into the cockpit of a 777. There is a technological elegance to everything that is there. But there are still hundreds (if not thousands) of individual switches, controls, displays, electronic gages and dials, menu driven control panels, etc. A great deal of human engineering has gone into everything that is in there so that for any given common task, there are only a couple of relevant controls that you have to touch and put into place to get the job done. The challenge is in knowing which one of those hundreds of knobs and dials to tweak.
The same is true for WCF. Microsoft has created an incredibly powerful and technologically advanced platform that is well adapted to building large distributed enterprise systems. In order to do that, there needs to be hundreds of switches and knobs that you can throw to address different scenarios. The downside to that is bullet number three above - you have to learn which switches and knobs are relevant for a given task, and in what order to throw them.
This is somewhat aggravated right now in that we are only at Beta 1 of WinFx (and its parts WCF, WPF, and WinWF), and the names, shapes, and locations of all the knobs and switches is constantly changing as they work on that human engineering task of trying to make it easier to use. Meanwhile the documentation and samples are seriously lagging, so working with it right now is a little like stepping into that 777 cockpit without any labels on the controls. When you say to yourself, "I just need transactions and certificate based security", it is kind of like saying "I just need to call the flight attendant at the second aft flight station". Simple to describe, but God help you in figuring out which switches and knobs to throw. At least there are not really any destructive ones that you can throw by accident. If you get it wrong, your app may not work, but you would have to go out of your way to write some code that would do bad things when WCF fails to let you communicate.
I'm looking forward to continuing to work with this technology and learn what all those knobs and buttons are for. Learning all the controls of the aft cockpit of the F-14 to run the weapons system, navigation systems, communications systems, and other tasks was one of the funnest things I have done in my life. The fact that we got to do that while strapped to a couple of 50K lb + of thrust zorching through the sky pulling G's and landing on the carrier certainly helped make it interesting. Sitting at a computer leaves a little to be desired in that department, but the learning challenge is still just as fun.
Thursday, October 27, 2005
Monday, October 24, 2005
Upcoming DevConnections Talks
I'll be speaking at Visual Studio Connections (part of DevConnections) in Las Vegas from 5-8 November. This is a great and growing conference that happens twice annually in the US, usually Orlando in the spring and Las Vegas in the fall, that I have been privileged to speak at for the last couple years. If you haven't been to one yet, you ought to be hammering your boss for permisson/funding to attend for the following reasons:
- It will rapidly and time-effectively expose you to new solution technologies you might not get a chance to explore on your own
- You will get concentrated advanced training in current and future technologies, getting you up to speed on them in far less time than you can achieve on your own
- You will get presentations from the top speakers in the business
- You will get a chance to network with peers in the industry, learn from others experiences employing .NET technologies, which will make you more effective at employing them yourself
- You will have a lot of fun (OK, maybe don't tell your boss this...)
You can learn a lot peripherally from the conference too by reading the DevConnections blog here. There are posts from other speakers as they develop their talks and their own observations and experiences at the conference.
I'll be presenting the following sessions:
VSM356: Build Custom Data Bound Business Objects and Collections VSM351: Secure Smart Client ClickOnce Deployments VID306: Build Event-Driven Applications with Indigo VID309: Connect Smart Client Applications with Indigo
If you make it to the show (and you should!!), stop by and say hi!
Two Upcoming MSDN Webcasts: Part of the "Best Of" Series
I've got two MSDN Webcasts coming up at the end of November, both part of the "Best Of" series that they are doing surrounding the launch of VS 2005 for those Webcasts focused on .NET 2.0 and VS 2005 that got the highest scores in the last year.
You can click through here to get to the webcasts:

The two I am giving will both be on 29 November:
Presenting Rich Rich Tabular Data with the DataGridView Control Tuesday, November 29, 2005 10:00 A.M.–11:00 A.M. Pacific Time
Deploy Smart Client Applications with ClickOnce Tuesday, November 29, 2005 1:00 P.M.–2:00 P.M. Pacific Time
Check them out!!
IDesign Site Facelift
Wednesday, October 12, 2005
Building Smart Client Data Applications with Windows Forms 2.0
I gave a talk at LexDotNet in Lexington KY last night on building smart client data apps. It really boils down to a similar talk to my Tackle Complex Data Binding with Windows Forms 2.0 talk, but with a slightly different approach and angle. I did mostly a large progressive demo where I started out with the simple and impressive data binding capabilties for working directly with a database in your Windows Forms app. Then I explained why you should never do that in a serious production application and stepped through how to migrate the functionality to a three or four layer/tier architect without giving up any of the capability of the data binding features in Windows Forms.
Here are the slides and demos that I used.
Thursday, September 29, 2005
On-Demand Updates with ClickOnce
ClickOnce supports both automatic updating and on-demand updates. The default model checks for updates automatically at application launch (when connected), and applies those updates immediately. There are a number of options available for installed applications (available online and offline), including whether to check automatically at all, whether to do it on a background thread, whether to do it on a timed interval, and other options.
However, sometimes you may want to do updates on demand, either as the only update model, or in combination with automatic updating in the background on a periodic interval. To do that, you will need to use the ClickOnce API defined in the System.Deployment framework assembly.
The main class you will use to support on-demand updates is the ApplicationDeployment class defined in the System.Deployment.Application. You will typically add code in response to a user action (such as selecting a Check For Updates menu item) that goes out and checks to see if updates are available, and if so retrieves them. You will then need to restart the application to have those changes applied.
A simple but common pattern to accomplish this is something like the following:
// First check to see if we are running in a ClickOnce context
if (ApplicationDeployment.IsNetworkDeployed)
{
// Get an instance of the deployment
ApplicationDeployment deployment = ApplicationDeployment.CurrentDeployment;
// Check to see if updates are available
if (deployment.CheckForUpdate())
{
DialogResult res = MessageBox.Show("A new version of the
application is available, do you want to update?",
"Application Updater", MessageBoxButtons.YesNo);
if (res == DialogResult.Yes)
{
// Do the update
deployment.Update();
DialogResult res2 = MessageBox.Show("Update complete, do you
want to restart the application to apply the update?",
"Application Updater", MessageBoxButtons.YesNo);
if (res2 == DialogResult.Yes)
{
// Restart the application to apply the update
Application.Restart();
}
}
}
else
{
MessageBox.Show("No updates available.", "Application Updater");
}
}
else
{
MessageBox.Show("Updates not allowed unless you are launched through ClickOnce.");
}
There are of course asynchronous versions of the CheckForUpdate and Update methods if you want to avoid blocking your UI while this happens.
The project settings you will need may not be completely apparent. The first important setting is that you need to change the update behavior of the ClickOnce deployment to stop automatically checking for updates if you are doing only on-demand updates. You do this through the Publish tab of the project properties settings, Updates button, shown in Figure 1.

Figure 1: ClickOnce Update Behavior Settings access
When you click that button, the dialog in Figure 2 will show with default settings selected as shown.

Figure 2: ClickOnce Update Settings Dialog
What you will want to do for a pure on-demand updates application is to uncheck the box that says the application should check for updates at the top. The other trick that is not apparent but required is that you have to specify an Update location at the bottom or you will get an obscure error message when you try to launch the application on the client. So you should set up the update settings like shown in Figure 3.

Figure 3: ClickOnce On-Demand Update Settings
With those settings in place, when you publish your application out and the client launches it, they can invoke the code shown earlier to check for and apply updates on-demand.
If you wanted to combine on-demand updates with periodic background checking for updates, you can do that by leaving updates enabled, but you will need to select the option to check for updates after the application starts. You will then want to configure the frequency of checking using the options in the middle of the dialog.
Smart Client Deployment with ClickOnce talks in St. Louis and KC
I gave a talk on ClickOnce in both St. Louis and Kansas City Monday and Tuesday evening this week and had a really good time. After the St. Louis talk I was able to go out for a beer with Bill Evjan, Scott Spradlin, and some of the other group members, which is always a great chance to network while I am there. KC was more of a quick strike since I had to fly out first thing in the morning to head to the MVP summit in Seattle.
The code samples and slides can be downloaded here.
Friday, September 23, 2005
Nice little SOA podcast
My associate Michele is part of a panel discussion podcast that Microsoft is doing on Service Oriented Architecture that will be ongoing over a period of time. The first one just hit the streets and is great. Check it out here.
Very nice little discussion of what matters.
.NET | Architecture  Friday, September 23, 2005 6:05:52 AM (GMT Daylight Time, UTC+01:00)  |
Wednesday, September 14, 2005
System.Transactions and connection pooling
Update: I had put this post up yesterday and then accidentally deleted it while trying to do an update due to a technical inaccuracy. Sorry if you get a duplicate post, if so use this one. The technical inaccuracy had to do with the section describing when the transaction is promoted to the DTC.
---------------
One of the reviewers of my Data Binding in Windows Forms 2.0 book raised a question regarding System.Transactions and connection pooling that is important to understand. I didn’t go into detail on this issue in the book (because it is not a data access book, it is a data binding book… you know completely different layers, hopefully separated by a business layer…).
The discussion centered around the following code snippet:
public void ExecuteTransaction()
{
CustomersTableAdapter adapter = new CustomersTableAdapter();
// Start the transaction
using (TransactionScope scope = new TransactionScope())
{
CustomersDataSet.CustomersDataTable customers;
customers = adapter.GetData(); // First query
customers[0].Phone = "030-0074321";
adapter.Update(customers); // Second query
scope.Complete(); // Commits the transaction
}
}
The code above opens a transaction scope and performs two queries within that scope. The call to Complete on the scope votes to commit the transaction. If there is no ambient transaction when this call is executed, a new transaction will be created when the scope is constructed. If there is an ambient transaction, this scope will be enlisted in the ambient transaction, and will not be committed until its enclosing transaction is committed.
The misunderstanding was that the reviewer thought that in order to scope the transaction across two queries (GetData and Update on the table adapter), Microsoft had implemented it by keeping the connection open, which would be a bad thing from a connection pooling perspective.
<UpdatedSection>
The truth is that transactions in System.Transactions have scope greater than a single connection. If the queries run against a single connection to a SQL Server 2005 database, then a lightweight transaction will scope the queries through that connection. If the queries run against more than one connection instance (as is likely with the code above or most multi-query scenarios) or any other resource manager other than 2005 at this point (i.e. SQL 2000, Oracle, MSMQ, etc.), then the transaction will auto-promote to a DTC transaction, which can obviously scope multiple connections.
</UpdatedSection>
In the code above, the connection is opened and closed automatically by the data adapter that is encapsulated in the table adapter for each of the calls (GetData and Update) in the same way as in .NET 1.1, regardless of the target database. The close doesn’t really close the connection, it puts it back on the connection pool. The transaction scope is greater than each connection and can span both connections, <UpdatedSection> after promotion to the DTC</UpdatedSection>.
In case you want to see it in action, you can download a simple sample here that demonstrates this fact. This sample makes similar calls to the above, but adds a partial class extenstion and method to the table adapter allowing you to check the connection state in between calls:
namespace SystemTransactionsSample.CustomersDataSetTableAdapters
{
public partial class CustomersTableAdapter
{
public bool IsConnectionOpen()
{
return Connection.State == System.Data.ConnectionState.Open;
}
}
}
If you insert a call to IsConnectionOpen on the adapter between GetData and Update, you will see that the connection is in fact in a closed state between calls, even though the transaction is alive and uncommitted.
Tuesday, August 30, 2005
Data Binding a ComboBox to a child collection
One of the most frequent questions I get regarding data binding is how to hook up a combo box with a data bound list of selections from a related table or collection, and have selections in that combo box set a corresponding value in the related collection. For example, in the following form, the main collection is the Products table from Northwind. The textboxes are displaying a couple of the columns from that table, and the combo box is displaying the supplier name from the related Suppliers table. Products contains a foreign key column with a SupplierID that makes the link.

The code required to hook all this up in .NET 2.0 is very simple, although maybe slightly difficult to discover on your own. The solution below binds the controls to two BindingSource components, which is the new way of doing data binding in .NET 2.0. The BindingSource component provides a layer of indirection between your bound controls and their data sources that makes synchronizing bound controls easier, allows you to switch out the data source without needing to re-initialize bindings, and exposes a number of useful events to monitor what is going on in bound data sources in your code.
Basically all you need to do is get your data and set that as the data source on the two binding sources. Then set up a normal ComboBox data binding on the ComboBox with the DataSource, DisplayMember, and ValueMember properties. You then add a simple binding to the control's DataBindings collection (an instance of a Binding object) that ties the SelectedValue property on the ComboBox to the corresponding foreign key property/column in the parent collection:
// Retrieve the data for products and suppliers into a data set or custom collections
// Set up the data bindings for the textboxes on the form to their binding source
// i.e. m_ProductNameTextBox.DataBindings.Add("Text", m_ProductsBindingSource, "ProductName", true);
// Set the BindingSource.DataSource property for the textboxes on the form
m_ProductsBindingSource.DataSource = m_Products; // some collection of products
// Set the binding properties for the combo box
m_SuppliersBindingSource.DataSource = m_Suppliers; // some collection of suppliers
m_SuppliersCombo.DataSource = m_SuppliersBindingSource;
m_SuppliersCombo.DisplayMember = "CompanyName";
m_SuppliersCombo.ValueMember = "SupplierID";
// Add a simple binding for the combo box SelectedValue property to the other collection
m_SuppliersCombo.DataBindings.Add("SelectedValue",m_ProductsBindingSource,"SupplierID");
The ComboBox databinding takes care of setting the SelectedValue property on the ComboBox whenever the current item in the parent collection changes.
The steps to regenerate the displayed sample in the Visual Studio 2005 designer are as follows:
- Create a Database Data Source (typed data set) through the Data Sources window to Northwind with Products and Suppliers tables in it.
- In the Data Sources window, change the control mapping for the Products table to Details (drop down the list of controls by selecting it and dropping it down)
- Set the control mapping for the SupplierID column of Products to ComboBox
- Set the control mapping of other columns you don’t want to display to None.
- Drag and drop the Products table onto a form. A binding source, binding navigator, the textboxes and the combobox will be generated with their labels.
- Select the ComboBox in the designer.
- Go to the Properties grid and select the (DataBindings) property (Advanced) subproperty. Select the ellipses (…) to get the dialog up.
- The Text property will have a Binding set up for it. Remove that by selecting the Binding drop down and selecting None at the top of the list.
- Select the SelectedValue property in the Advanced Bindings window and select the productsBindingSource.SupplierID as the bound column. OK out of there.
- Go back to the Data Sources window and drag the Suppliers table onto the ComboBox. This will hook up the DataSource, DisplayMember, and ValueMember properties.
Hope that is helpful to those groping around with similar data binding scenarios out there.
Data Binding in Windows Forms 2.0 - Final Manuscript Done!
Phew! After a year and a half of trying to keep pace with the changing betas and writing the book on top of a full schedule of consulting, training, and speaking at conferences and user groups, I am finally done. I submitted the final manuscript to production on Friday. Now I just have to respond to any questions and reviews during the production phase, convert the code samples to VB for download, and I can call this one a wrap.
You can order the book here (available January 2006):
http://www.amazon.com/exec/obidos/ASIN/032126892X/qid=1124482085/sr=11-1/ref=sr_11_1/102-1031358-5664119
We will have a teaser chapter out at PDC that will also be available for download as a PDF containing part of the chapter on the DataGridView control. I'll put up a link to that as soon as it is available.
Now I am start devoting my attention to my next book, Smart Client Deployment with ClickOnce, also part of the Addison Wesley .NET Development series. I hope to knock this one out in the next 6 months, so it should hit the shelves mid 2006.
Tuesday, August 2, 2005
Advanced .NET Master Class Oct 17-21, Reston VA
I'll take the opportunity here for some shameless self-promotion...
If you are an intermediate to advanced developer who already has some .NET experience and are looking to take it to the next level, you might want to check out our Advanced .NET Master Class, which I will be teaching in Reston, VA from 17-21 Oct. This is a public offering of a high-demand course that we normally only offer onsite for larger development teams. You can find the full class description here. This will be a well-timed, comprehensive, in-depth coverage of developing enterprise applications in .NET 2.0. I cover a huge amount of material including advanced language features in C#, assemblies and versioning, serialization, multi-threading, transactions, security, Enterprise Services, and Remoting.
If you are interested, contact us through this link to obtain more information.
Friday, July 29, 2005
Speaking and Drinking in Tampa last night
I had a great time speaking at the TampaBay .NET Users Group last night. We had a great turn out and it was a fun crowd. About 20 of us retired to a nearby bar afterwards for some suds and good conversation. Apparently they do that fairly regularly at their group. That is definitely the largest interactive mass of people I have encountered at a user group that goes out and really networks and has a good time together after the meeting on a regular basis.
Thanks for having me down guys and gals!!
The talk was on ASP.NET 2.0 Data Binding, and was a little rough since it was the first time I had given this talk. But hopefully people still got a lot out of it. I did all the demos on the fly, and as a result, a few of them didn't work out because I decided to take a few little side trips that I had not practiced, which is never a good idea on stage with new material.
If you are interested, here are the slides and outcome of the demos.
Friday, July 8, 2005
Wednesday, July 6, 2005
Tuesday, July 5, 2005
Using User Settings in Partial Trust
In my previous post on ClickOnce custom install steps, I talked about how to read and write custom settings from Isolated Storage. One thing I purposely avoided mentioning there (because I needed to get confirmation on some facts from the product team at Microsoft) was the use of the new User scoped settings in .NET 2.0 and Visual Studio 2005.
If you are not already aware, the approach to config files has changed quite a bit in .NET 2.0. When you create a project in Visual Studio 2005, you can add custom settings through the project property pages (Settings tab), and those will be persisted in your config file and available to you at runtime. Additionally, strongly typed properties are added to a Settings class that is created by the designer so that you can access those settings programmatically with code like this:
string myCustomString = Properties.Settings.Default.MyCustomString;
The Settings class is declared in a child namespace of your project namespace called Properties, and the Settings class has a singleton property called Default that you use to get a reference to the one and only one instance of the Settings class for your app. From there, you just access the settings in your config file through named strongly typed properties.
That on its own would be a big win from a design time and compile time perspective, but the full story is even better. For one thing, you can designate whether settings are scoped to the application or to the user. If scoped to the application, then the settings go in your application configuation file as usual (<appname>.exe.config or web.config as appropriate). If scoped to the user, the settings go into a slighly obfuscated directory under the user's profile, under <username>\Local Settings\Application Data\.
The other thing about user settings is that all the properties for them that get exposed through the Settings class are both read and write. So you can set the properties, call Save on the settings class, and your changes will be written out to the user config file:
Properties.Settings.Default.MyCustomString = "SomeNewValue";
Properties.Settings.Default.Save();
So for the scenario I was describing in the previous post about writing out a flag to indicate when it is no longer the first time you application has run, a boolean user setting is cerrtainly a prime candidate for a place to put that. And if you read the docs for user settings, you will see that it says that you can write to user settings in partial trust, so it should be a winner for ClickOnce deployed apps as well. The reason I held off on mentioning it in the other post is a typical story:
User Settings do not work in partial trust in Beta 2.
If you try to write out user settings (call Save) in a partial trust environment in Beta 2, you will get a FileIOPermission security exception thrown. The thing I was waiting for confirmation on was that this will be fixed for RTM, and the answer was yes. So for production apps releasing after RTM, you can do all your ClickOnce custom settings through user settings, and not have to write explicitly to IsolatedStorage. There may still be some scenarios where you want more explicit control over the I/O process, in which case Isolated Storage is still your best option for a ClickOnce app to minimize your permission requirements.
Monday, July 4, 2005
How to handle prerequisites and custom install steps for a ClickOnce Deployed Application
UPDATE: There was one little hitch with the code I presented earlier in this posting... it didn't work in partial trust because the BinaryFormatter and serialization require security permissions that are not granted in partial trust. At the end of the posting is the new code that does work fine in partial trust, but only works for built-in basic types in .NET (int, string, bool, etc.) because a custom XmlSerializableHashtable was required to get things working. The full code can be downloaded here. It is also available on the IDesign web site, download tab at http://www.idesign.net/. The code below has been updated to show the full source of the helper class and the XmlSerializableHashtable, which was adapted from the one in the Configuration Management Block. One of the other improvements that were made at my colleague Juval Lowy's prompting was to make the Read and Write methods generic so that they could read and write in a type safe way instead of using object parameters and return types, which was an excellent suggestion.
-----------------
These are some common questions I get about ClickOnce:
"My app depends on XXX, how can I ensure it is on the user’s machine before trying to launch my ClickOnce app?"
"I need to do XXX the first time the app is run, how can I do this from ClickOnce?"
Prerequisite Detection
The answer to the first question is twofold. First, there is the issue of detection. There is no general way to do prerequisite detection across the board. It is going to depend a lot on what those prerequisites are. In some cases, you may be able to use WMI, in others, File I/O to look for some known signature in an expected folder. In almost all of these approaches, you are going to need highly elevated permissions on the box, both from the perspective of the user that executes the application, and second from a Code Access Security (CAS) perspective.
Probably a better way is to have some startup code in your application that only runs once for a given version that attempts to use the APIs (directly or indirectly) of the prerequisites that you depend on. If that attempt fails, catch the exception and notify the user that they are lacking the respective prerequisite. If it is MDAC or SMO or something like that, try to use the calls that your app uses that calls through those layers (to do something trivial and non-destructive obviously). I’ll talk about strategy for managing one-time steps like this in your ClickOnce apps towards the end of this post.
Prerequisite Installation
The second part of the answer to the question on dependencies is to use the bootstrapper. This is a new feature in .NET 2.0 that is not technically part of ClickOnce, but ClickOnce capitalizes on it for getting prerequisites deployed. Using the bootstrapper, you can wrap up all the MSI installs that need to be run for prerequisites for your app into one setup.exe that an admin needs to run on the client box just once. It will run each of the prereq setup packages as needed, and then you should be good to go to run your ClickOnce app.
If your deployment environment is a controlled intranet environment, then managing this through group policy/SMS/basic client machine configuration control should be sufficient. You have an admin for your domain somewhere that has configuration control over the user’s desktops, get them to roll out the prereqs necessary to support your application. If your target audience is open internet users, then you will have to provide them a link to the bootstrapper setup.exe that they run first (and they will have to be an admin on the box to do so), and then they can run your ClickOnce app.
One-Time Setup Steps
The answer to the second question – how to do one-time actions for your ClickOnce app before it runs – is actually fairly simple to solve, even though ClickOnce provides no direct mechanisms for doing so. By design, ClickOnce does not allow you to configure or run any custom install steps as part of the ClickOnce deployment. The idea is that there should be no way the act of deploying a ClickOnce app to a client machine will corrupt other applications or other user data on that machine. If they opened the Pandora box of allowing custom install actions, there would be no way to guarantee that. However, once your app is on the machine and executing, it can do whatever it was designed to do, provided it has sufficient CAS permissions and that the user is authorized to access whatever resources they are trying to access.
For example, say that the first time you run your application, you need to prompt the user for the name of the database server and database name (obviously a power user requirement – something more simple would be just prompting them for their name and initials like Office apps do the first time they are run). Once you prompt the user for that information, you need to store it somewhere. You also have to have logic in your app to know to only prompt the user for that information the first time the app is run, so you need a flag somewhere to detect when that is the case.
Well, one of the simplest ways to do this is to use the data you are collecting for these situations as the flag themselves. If it is some other kind of one time action you need to run that doesn’t generate stored data, then you will need a separate flag that is easy to read and check at app startup. So all you need to do is have some internal startup code in your app that checks for the first time run flag, or checks for the presence of the needed data, and does appropriate prompting if not.
Once you have collected the data, you need to persist it for the next run, whether it is a simple first-time-run flag, or whether it is the database server and database name example mentioned above. You could just write it out to some file in your application directory, but that is going to require File I/O permission. You app will not have that permission by default in a ClickOnce deployed app on the internet or local intranet, unless you deploy it requesting elevated permissions. You should avoid asking for more permissions than you really need, and if this is the only File I/O your app does, then a better choice is to use Isolated Storage.
Reading and writing to Isolated Storage is permitted in both the Internet and Local Intranet CAS zones for AppDomain isolation, so you don’t need any elevated permissions to be able to read and write your config settings there. There is a new level of isolation in .NET 2.0, scoped to the application level (as opposed to the assembly and AppDomain levels present in earlier versions of .NET). Application scoped isolated storage settings will be accessible regardless of the version of your application when ClickOnce deployed, so you won’t lose these settings when the application is updated. However, if you want your app to check for pre-reqs each time the app is updated, maybe writing that flag to an appdomain scoped isolated storage is exactly what you want, because then the setting will be refreshed for each update.
Writing to isolated storage is fairly straightforward. You create an instance of an IsolatedStorageFile scoped to the appropriate isolation level through the exposed factory methods. You then create an IsolatedStorageFileStream, and from there it is just straight I/O against a stream, the same as you would do for a normal file in .NET.
I wrote a little helper class to make this as easy as possible to read and write settings from isolated storage, both in ClickOnce and non-ClickOnce applications. The IsoStoreSettingsHelper is shown below. To use this as is, you will need to set a reference to the System.Deployment.dll assembly in the framework, and will need the using statements shown below. The Read and Write methods take the name of file you want to use or create for storing settings within isolated storage. The Read method attempts to read a named setting from the specified file name in isolated storage. If the file does not exist, does not contain a hashtable, or the setting key specified cannot be found, then null will be returned. Otherwise the value from the hashtable will be returned. When write is called, it will add the specified key/value pair to the settings file, and will create it if it does not already exist.
The code dynamically selects either isolation by domain or isolation by application based on whether the application has been ClickOnce deployed. The reason for this is that application isolation depends on an identity for an application that is only present in a ClickOnce deployed app. So you cannot use application isolation unless you are running through ClickOnce. It checks for this with the IsNetworkDeployed property on the ApplicationDeployment class.
UPDATED CODE:
IsoStoreSettingsHelper class:
using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Deployment.Application;// Need to add reference to System.Deployment.dll framework assembly
namespace IDesign.Utilities
{
public static class IsoStoreSettingsHelper
{
/// <summary>
/// Reads a setting from isolated storage.
/// Assumes isolation by domain for non-ClickOnce deployed apps.
/// Assumes isolation by application for ClickOnce deployed apps.
/// </summary>
/// <param name="fileName">The name of the settings file to use.</param>
/// <param name="key">The key name of the setting to look up.</param>
/// <returns>The value stored in the file if found, the default value for the type otherwise.</returns>
public static T Read<K,T>(string fileName,K key)
{
try
{
IsolatedStorageFile isoFile = OpenIsoStoreFile(fileName);
string[] files = isoFile.GetFileNames(fileName);
if(files.Length == 0 || files[0].Length == 0)
{
// File does not exist, return default
return default(T);
}
// File exists, deserialize the settings
using(Stream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, isoFile))
{
XmlSerializableHashtable settings = XmlSerializableHashtable.Load(stream);
if(settings == null)
{
return default(T);
}
return (T)settings[key];
}
}
catch
{}
return default(T);
}
/// <summary>
/// Write a setting to an isolated storage setting file.
/// Assumes isolation by domain for non-ClickOnce deployed apps.
/// Assumes isolation by application for ClickOnce deployed apps.
/// </summary>
/// <param name="fileName">The name of the settings file to use.</param>
/// <param name="key">The key name of the setting to look up.</param>
/// <param name="value">The value of the object to store.</param>
public static void Write<K,T>(string fileName, K key, T value)
{
try
{
IsolatedStorageFile isoFile = OpenIsoStoreFile(fileName);
XmlSerializableHashtable settings = null;
// First try to read in existing settings is there are any
using(Stream stream = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, isoFile))
{
try
{
settings = XmlSerializableHashtable.Load(stream);
}
catch
{
}
if(settings == null)
{
settings = new XmlSerializableHashtable(); // Create empty one for new settings
}
}
//Add the new setting to the collection
settings[key] = value;
//Now write the collection back out
using(Stream writeStream = new IsolatedStorageFileStream(fileName,FileMode.Create,isoFile))
{
settings.Save(writeStream);
}
}
catch
{ }
}
static IsolatedStorageFile OpenIsoStoreFile(string fileName)
{
IsolatedStorageFile isoFile = null;
if(ApplicationDeployment.IsNetworkDeployed)
{
isoFile = IsolatedStorageFile.GetUserStoreForApplication();
}
else
{
isoFile = IsolatedStorageFile.GetUserStoreForDomain();
}
return isoFile;
}
}
}
XmlSerializableHashtable class:
using System;
using System.Collections;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace IDesign.Utilities
{
// Support storage of .NET primitives
[XmlInclude( typeof(string) )]
[XmlInclude( typeof(bool) )]
[XmlInclude( typeof(short) )]
[XmlInclude( typeof(int) )]
[XmlInclude( typeof(long) )]
[XmlInclude( typeof(float) )]
[XmlInclude( typeof(double) )]
[XmlInclude( typeof(DateTime) )]
[XmlInclude( typeof(char) )]
[XmlInclude( typeof(decimal) )]
[XmlInclude( typeof(UInt16) )]
[XmlInclude( typeof(UInt32) )]
[XmlInclude( typeof(UInt64) )]
[XmlInclude( typeof(Int64) )]
public class XmlSerializableHashtable
{
#region Nested Class--Entry
/// <summary>
/// Represents an entry for the hashtable
/// </summary>
public class Entry
{
private object m_EntryKey;
private object m_EntryValue;
/// <summary>
/// Default constructor, needed by serialization support
/// </summary>
public Entry(){}
/// <summary>
/// Construct the Entity specifying the key and the entry
/// </summary>
/// <param name="entryKey"></param>
/// <param name="entryValue"></param>
public Entry( object entryKey , object entryValue )
{
m_EntryKey = entryKey;
m_EntryValue = entryValue;
}
/// <summary>
/// Return the key
/// </summary>
[XmlElement("key")]
public object EntryKey
{
get{ return m_EntryKey; }
set{ m_EntryKey = value; }
}
/// <summary>
/// Return the entry value
/// </summary>
[XmlElement("value")]
public object EntryValue
{
get{ return m_EntryValue; }
set{ m_EntryValue = value; }
}
}
#endregion
#region Declarations
private Hashtable m_HashTable;
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public XmlSerializableHashtable()
{
m_HashTable = new Hashtable();
}
/// <summary>
/// Creates a serializable hashtable using a hashtable
/// </summary>
/// <param name="ht"></param>
public XmlSerializableHashtable( Hashtable existingHashTable )
{
m_HashTable = existingHashTable;
}
#endregion
#region Public Methods & Properties
/// <summary>
/// Indexer to access the underlying Hashtable
/// </summary>
/// <param name="key">The key for which you want to retrieve the value</param>
/// <returns></returns>
[XmlIgnore]
public object this[object key]
{
get
{
lock (m_HashTable.SyncRoot)
{
return m_HashTable[key];
}
}
set
{
lock (m_HashTable.SyncRoot)
{
m_HashTable[key] = value;
}
}
}
/// <summary>
/// Save the hashtable to an output stream
/// </summary>
/// <param name="outputStream">The stream to write to</param>
public void Save(Stream outputStream)
{
XmlSerializer serializer = new XmlSerializer(typeof(XmlSerializableHashtable));
serializer.Serialize(outputStream,this);
}
/// <summary>
/// Load a hashtable from an input stream
/// </summary>
/// <param name="inputStream">The stream from which to load</param>
/// <returns>A new instance of an XmlSerializableHashtable</returns>
public static XmlSerializableHashtable Load(Stream inputStream)
{
XmlSerializer serializer = new XmlSerializer(typeof(XmlSerializableHashtable));
return serializer.Deserialize(inputStream) as XmlSerializableHashtable;
}
/// <summary>
/// Returns the contained hashtable
/// </summary>
[XmlIgnore]
public Hashtable InnerHashtable
{
get{ return m_HashTable; }
}
/// <summary>
/// Used to serilalize the contents of the hashtable
/// </summary>
public Entry[] Entries
{
get
{
lock (m_HashTable.SyncRoot)
{
Entry[] entries = new Entry[m_HashTable.Count];
int index = 0;
foreach (DictionaryEntry entry in m_HashTable)
{
entries[index] = new Entry(entry.Key,entry.Value);
index++;
}
return entries;
}
}
set
{
lock( m_HashTable.SyncRoot )
{
m_HashTable.Clear();
foreach( Entry item in value )
{
m_HashTable.Add (item.EntryKey,item.EntryValue);
}
}
}
}
#endregion
}
}
Wednesday, June 29, 2005
ClickOnce certificates in a nutshell
I have gotten a lot of questions surrounding the use of certificates in ClickOnce. Here are the key facts to understand:
- You must sign your ClickOnce manifests with an Authenticode certificate. VS 2005 will do this for you when you publish an application.
- Authenticode certificates are not the same thing as an SSL certificate or an X509 client certificate used for authentication purposes, even though they are all based on the same technology.
- You can generate your own certificate using Visual Studio, or the makecert command line utility. In this case, you are both the publisher represented by the certificate and the certificate issuing authority. You will sometimes see this referred to as a self-signed certificate.
- A third party issued certificate (i.e. Verisign, Thawte) is the preferred approach. These companies are already configured in Windows as trusted root certificate authorities (CA), and because they are third party verified, there is an additional level of implied trust associated with them.
- If you are part of a large enterprise domain and you have a domain CA, that CA can issue you a publisher cert for your domain that you can use, and your publisher certificate can be pushed out to client machines through group policy or SMS.
- If user prompting is acceptable for elevating privileges (based on the permissions requested by the application in its manifest and the permissions that would be granted by code access security based on the launch URL), then there is no need to install any certificates on the client side.
- If you want to avoid user prompting, you need to install your publisher certificate in the Trusted Publishers store on the client machine.
- At runtime, certificate checks are only done against the local certificate stores on the client machine. Specifically, the certificate used to sign the manifests is checked for in the Trusted Publishers store, and the issuer of that certificate is checked for in the Trusted Root Certificate Authorities store.
If you want more information on configuring certificates and how they work at runtime, you should check out my article on MSDN Online:
http://www.msdn.microsoft.com/library/en-us/dnwinforms/html/clickoncetrustpub.asp
Wednesday, June 22, 2005
Sunday, June 19, 2005
Thursday, June 16, 2005
ClickOnce On-Demand Update Bug in Beta 2
In case you stumble and fall over this like I did, there is a bug in Beta 2 for configuring ClickOnce on-demand updates through the API. Normally if you wanted to support on-demand updates in a ClickOnce application, you would set it to not check for updates through the Updates settings in the Publish category of project properties in a Windows Forms project. You would then write code like the following in your application to support an on-demand update check (either programmatically or based on user request):
using System.Deployment.Application;
public partial class Form1 : Form
{
private void OnDemandUpdate(object sender, EventArgs e)
{
if (!ApplicationDeployment.IsNetworkDeployed)
{
MessageBox.Show("This application deployment does not support network updates.");
return;
}
ApplicationDeployment deployment = ApplicationDeployment.CurrentDeployment;
Cursor currCursor = this.Cursor;
this.Cursor = Cursors.WaitCursor;
if (deployment.CheckForUpdate())
{
deployment.Update();
this.Cursor = currCursor;
DialogResult result = MessageBox.Show("Update Complete. Restart?", "ClickOnce On-Demand Update", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
Application.Restart();
}
}
else
{
MessageBox.Show("No updates available");
}
this.Cursor = currCursor;
}
However, if you did this in Beta 2, you get an exception when this code runs with an IllegalOperationException saying this application cannot be updated programmatically. The workaround in Beta 2 is to tell the app to check for updates, set it to do so after the application starts, and set the subscription period (how often to check for updates) to a long value, such as 50 weeks. Be careful, because another bug is that VS will let you set an illegally large value for this subsciption, such as 512 weeks. If you do so though, you will get a deployment error because ClickOnce will see a schema violation, and if you try to edit the manifest with MaGe, it will crash with an unhandled exception. This should all be fixed by RTM, but are things to be aware of if you are playing with ClickOnce now or especially if you will be going to production with an application that uses this capability.
Saurabh Pant has a good post summarizing the specific settings that go in your manifest for this here.
Smart Client Offline Data Caching and Synchronization Demos
Here are the demos I gave in my TechEd session on Friday of last week. Sorry it took me a bit to get them posted. Call it post-conference-traumatic-stress-letdown-syndrome that made me go stupid.
Smart Client Offline Demos
Get a FREE copy of VS 2005 and SQL 2005 at DevConnections in Vegas
This is pretty cool. Hopefully by now you have heard that Microsoft officially announced the release date for Visual Studio 2005 and SQL Server 2005 as 7 November. What you may not have noticed is that is the opening day of the DevConnections conference in Vegas. Well, if you were not sure whether you should come to this outstanding conference before, maybe this will change your mind: you will get a free fully licensed copy of Visual Studio 2005 and of SQL Server 2005. The specific versions they are going to give out has not yet been determined, but hopefully they will be generous and go with Pro/Standard at least. They will also have a live broadcast of the Microsoft launch event in San Francisco, at which either Bill Gates or Steve Balmer will be speaking.
And if you happen to come to the show, come check out the talks I'll be giving, which include:
- Connect Smart Client Applications with Indigo
- Build Event Driven Applications with Indigo
- Secure Smart Client ClickOnce Deployments
Wednesday, June 8, 2005
Me and My, This and That
VB programmers have a pretty cool feature to wave in the faces of C# programmers in 2005 with the My feature... or do they? If you are not familiar with the My feature, it is a new keyword in VB2005 that you can type, and when you hit the . (dot) key, you will have instant access to a ton of common things such as the file system, user identity, network, and so on through some easy to use properties.
So VB has Me and My, why shouldn't C# have this and That? My colleague Juval has implemented a That class that exposes all the capabilities of My from VB to C# developers. It uses the same syntax and approach as My, just type That. and navigate through the object heirarchy to find the features that you want.

You can find the code for That on our downloads page at IDesign: http://www.idesign.net. Look for the link on the downloads page to "My for C# 2.0", or you can grab it here.
All My (and That) do is give you shortcut access to the most common features that people code against. Ultimately, you can achieve the same thing by finding the appropriate class in the .NET framework and invoking its functionality. But My (and now That) make it a lot quicker and easier to code up common scenarios.
In case you are a hard core C# guy who thinks this is just a joke and are thinking that there is no point, consider if you find some VB 2005 code in a sample that does what you want, but they are making extensive use of the My feature. How do you port that code to C#? Without the That class, you will have to rewrite anything that is using My. With the That class, you can just migrate it directly with little to no syntax conversion. The same would be true if you were going to migrate a complex VB 2005 app to C#.
Obviously since That is kind of a play on words, and we provide you the source code, you could change That to My and have the same name for the class as in VB. But That kind of has a nice ring to it. :)
Hats off to Juval for throwing this together in the wee hours
Sunday, June 5, 2005
Back in Conference Land at TechEd
I just got back from Holland Thursday after speaking at SDC there, and now I am in Orlando to speak at TechEd. These things are nothing but fun, but man, the travel can get crazy.
I had a great time last night joining in with the crowd at the Party with Palermo, which evolved from a loosely organized geek dinner into a great gathering of speakers, RDs, MVPs, and attendees in the Peabody hotel restaurant and bar. Today there are a collection of overlapping events that I plan to try to attend portions of, including some MVP events, the INETA summit, and some of the pre-con sessions.
The rest of the week is already pretty packed. My breakout session is not until Friday, but I have a bunch of other things I am participating in / presenting as well:
Tuesday 7 Jun:
3:15-6:15 PM- proctoring Juval Lowy's Instructor Led Lab (ILL) on Generics (DEV20/DEV20R)
9:00 - 10:00 PM - Preparing for Indigo Birds of a Feather (BoF) given by Juval
Wednesday 8 June:
8:30 AM-11:30 AM- proctoring Michele Leroux Bustamante's ILL on Iterators (DEV23/DEV23R)
7:00-11:00 PM Influencer Party
9:00-10:00PM Leading BoF session on Smart Client Deployment (BOF051)
Thursday 9 June:
3:15 - 6:15 PM - Giving System.Transactions ILL (DEV 22/22R)
Friday 10 June:
10:15 AM -12:00 PM - Answering Q&A questions through LiveMeeting for Juval Lowy's Simulcast session Being More Productive with the .NET Framework (DEV325)
1:00 - 2:15 PM - Presenting CLI440 Smart Client Offline Data Caching and Synchronization
Those are just the items that warrant an unchallenged block on my calendar. There are a ton of other events mixed in there as well to keep the week packed. I also need to get some more work done on my book this week getting the second half of the book up to date with Beta 2 and ready for Tech review, and also want to try to blog a few technical posts about stuff I am working on. Hmm, when is thattime expansion device going to be on the market??
Thursday, June 2, 2005
Northwind No Mas? Not so fast
UPDATE: I just realized the link that I refer to is not in here. Here it is:
http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034&displaylang=en
I was informed by my friends Richard Campbell and Steve Forte the other day in Holland at SDC that Northwind will not ship with SQL Server 2005. I was a little bummed, because I have used it for a lot of the samples in my book because I was told by certain contacts at Microsoft that it would ship with 2005, and I wanted to maintain backwards compatibility with folks who have not migrated to SQL Server 2005 yet (I think Whidbey adoption will be much faster in development shops than SQL Server 2005 for licensing reasons).
Well, just in case this is a surprise to you to, and you want to be able to add Northwind to SQL Server 2005 after you install it, here is a link to the sample DBs (Northwind and Pubs) as scripts that should work fine with 2005 as well.
Tuesday, May 31, 2005
Slides and Demos from SDC 2005 Netherlands
I gave 4 sessions at the Software Developers Conference 2005 in Arnhem, Netherlands yesterday and today. Great little conference and a lot of fun to get to speak at.
Here are the slides and demos from the sessions:
Smart Client Offline Data Caching and Synchronization: slides demos
Extending ASP.NET with Custom Handlers and Modules: slides demos
Smart Client Communications with the Middle Tier: slides demos
Tackle Complex Data Binding with Windows Forms 2.0: slides demos
Friday, May 20, 2005
Friday, May 13, 2005
David Chappell on Indigo
I attended a developer dinner put on by the local Microsoft office ( G. Andrew Duthie specifically) last night that was truly excellent. David Chappell was the speaker and I enjoyed his talk immensely, as I do all his talks. The talk was a basic intro to Indigo, and even though I was up to speed already on most of the content, it is always entertaining and educational to watch a masterful speaker spin his web. He did a great job explaining some of the more complex aspects of Indigo in ways that anyone could get. He has been doing a road show with this talk across the country and will be going to Atlanta next, so if you have a chance to see it there, you should.
Sunday, May 8, 2005
Slides and demos from Mid-Atlantic Code Camp
For those who attended, I hope you had a good time! Andrew did a great job putting the code camp together, and it seemed to go well all day.
Here are the slides and demos I gave:
Smart Client Offline Data Caching and Synchronization: Slides Demos
Secure Smart Client Deployment with ClickOnce: Slides Demos
Complex Data Binding in Windows Forms 2.0: Slides Demos
Sunday, May 1, 2005
Wednesday, April 27, 2005
Fun time at Tulsa.NET UG
I gave a talk at Tulsa .NET Users Group on Monday 25 Apr on Windows Forms 2.0 Data Bining and had a great time. The group is large and growing, standing room only with over 40 folks. The group is well led by Caleb Jenkins, he is a great MC and keeps the group very dynamic and motivated.
Here are the slides and demos.
Philly Code Camp wrap up
It took me a few days to get to it, but here are the slides and demos from Sunday's talks at Philly Code Camp:
Smart Client Offline Data Caching and Synchronization: Slides Demos
Secure Smart Client Deployment with ClickOnce: Slides Demos
Sunday, April 24, 2005
3 Down, 2 to go
I'm speaking at the Philly Code Camp this weekend, and gave three talks today, and two tomorrow.
As promised to the attendees, here are the slides and demos from today for:
DataGridView Control: Slides Demos
Complex Data Binding in Windows Forms 2.0: Slides Demos
Extending ASP.NET with Custom Handlers and Modules: Slides Demos
Monday, April 18, 2005
Wednesday, April 13, 2005
Extending ASP.NET talk slides and demos from Texas
I had a great time speaking at the Austin .NET Users Group and Texas A&M .NET User Group last night and today, giving my talk on Extending ASP.NET with Custom Handlers and Modules
For those that attended, or others that are interested, here are the slides and demos that I gave. If you have grabbed earlier versions of these from when I have given the talk in the past, you may want to grab the demos again since I added a custom handler demo that does watermarking of images that I wrote on the plane ride to Texas monday.
Monday, April 11, 2005
Speaking at Austin .NET and Texas A&M .NET User Groups
If you are a Texan and live in the Austin or College Station area, come on out to the Austin .NET Users Group on 11 April or the Texas A&M .NET Users Group on 12 April to see my Extending ASP.NET with Custom HTTP Handlers and Modules talk. I will be covering the ASP.NET processing pipeline, how/why to create custom handlers as endpoints for ASP.NET requests, and how to create custom modules to perform per-request processing across your application.
Hopefully them Aggies won't throw a lynching party afterwards since I am a boat school graduate...
Tuesday, April 5, 2005
Deploying and Launching non-Whidbey Apps with ClickOnce
A common question when I give talks on ClickOnce is whether you can deploy legacy applications with ClickOnce. The answer depends on how legacy you mean.
If you have an existing managed (.NET) application that will run fine against the .NET framework version 2.0, then you can deploy it using ClickOnce, without needing to rebuild the application using Visual Studio 2005. To do so, you will have to create the directory structure in which to place your application on the deployment server, and can then use the MAGE tool to author and sign application and deployment manifests for the application.
The thing to realize is that when your application is deployed this way, it will be launched inside the host process created by ClickOnce (currently named AppLaunch.exe), which loads the .NET rumtime version 2.0 to host the application. Based on the way .NET runtime and framework unification work, that also means that the version of the .NET Framework class libraries that you will be running against will be the 2.0 versions. If your legacy .NET application uses any features in the framework that have breaking changes between 2.0 and past versions, you might encounter errors when your app is running through ClickOnce that you never experienced before. You also have to realize that the application might be running in partial trust depending on how you configure the security permissions in your application manifest, so that could prevent certain operations in your application that used to work fine when not executed through ClickOnce.
If you app is REALLY legacy (i.e. VB6, MFC, ATL, etc.), as in an unmanaged code executable, then no, you cannot deploy it as an executable through ClickOnce. The MAGE tool takes a look at the executable that you select as the entry point for the application, and won't let you specify an unmanaged executable as the entry point. Without an entry point, you don't have a valid launchable ClickOnce application.
Are there workarounds? Of course!! There are always workarounds. If the unmanaged code you are trying to deploy is in the form of a library, there is nothing stopping you from consuming unmanaged code from a ClickOnce application, provided that the ClickOnce application is granted either full trust, or at least the unmanaged code execution security permission through the application trust for the ClickOnce application deployment. If you really want to launch an unmanaged executable through ClickOnce, you could write a very simple shim managed application with .NET that just does a Process.Start. Again, you will need unmanaged code permission for that to work.
A simple example is available here.
Sunday, March 27, 2005
Wednesday, March 23, 2005
Tuesday, March 22, 2005
Sunday, March 20, 2005
Friday, March 18, 2005
Visual Studio Extensibility
Last night I gave a talk on Visual Studio Extensibility to the BaltoMSDN User Group in Hunt Valley Maryland. Great group, had a lot of fun. If you attended or would like to check out the slides and demos, here is a link:
http://www.softinsight.com/downloads/VisualStudioExtensibility.zip
Just to actually put a little technical content on my blog for a change, I thought I would summarize a few key points from the talk.
Extensibility Options: You have several options for adding functionality to Visual Studio. The first and simplest are Macros. Visual Studio Macros are code that you can either generate with the Macro recorder (similar to recording macros in Office applications) or write yourself through the Macros IDE, a scaled down version of Visual Studio for macro development that you access through the Tools > Macros menu. Macros are a good way to automate simple repetitive tasks to save yourself keystrokes and mouse clicks that you do over and over for a given development task.
The next step up the pyramid are Visual Studio Add-ins, which were the focus of my talk. Add-ins allow you to write .NET components that plug into Visual Studio and can run in the background and handle events fired by VS as the developer interacts with it, and/or invoke custom code based on user keystrokes or command bar/menu button clicks. You can add custom UIs to Visual studio as dialogs, docking windows, or options panes. There are a bunch of good examples available from MSDN at:
http://www.microsoft.com/downloads/details.aspx?FamilyId=3FF9C915-30E5-430E-95B3-621DCCD25150&displaylang=en
To get really rich functionality like you may have experienced from retail developer tools that integrate into Visual Studio, you will need to tap into the Visual Studio Integration Partner (VSIP) SDK. You can download and use the SDK for free, but if you ship any products to customers that you developed with VSIP, licensing fees and restrictions can apply.
I was just made aware of another option that I have not yet explored in depth, but that looks very promising and intriguing. Developer Express, who produce CodeRush and soon Refactor! for Visual Studio .NET, have packaged their core framework for developing add-ins as a reusable class library that you can use to develop extensions to Visual Studio. Basically they hide all the arcane details of the VS object model and the COM interop layers you have to go through for programming straight add-ins and VSIP code, and instead give you a cleaner, managed object model to program against. It is called DXCore and you can get it here:
http://www.devexpress.com/Downloads/NET/DXCore/
I am a huge and vocal fan of CodeRush and now Refactor!, which not only save me a lot of time writing code, they make great motivational demos of the kinds of things you can achieve with extensibility in VS.NET. The fact that DevExpress has made the engine that they build these tools on for other to use is just another great example of the .NET community and I thank them for doing so. I'm looking forward to playing with these capabilities.
Add-in Gotchas: Some things to be aware of when building Add-ins (not using DXCore)... - When you create an Add-in project through the wizard, make sure you compile right away before doing anything. This is because the project wizard adds the registry settings to try and load your Add-in the next time VS starts up. If you don't build your project, those reg keys are pointing to a non-existent DLL, and you will get an error message that if you say Yes to, will kill all the reg settings you need to build/debug your Add-in. You can get them back by building and running the setup project that is created by the wizard, but it is a better practice to just do a quick build to get something there for VS to refer to after completing the wizard. - If you move your project to another machine, those reg keys will not be there to allow you to debug the add-in. The easiest way to get them in place is to build the Add-in project, build the setup project that is part of the solution, run the install, and then rebuild the Add-in project. Running the install will install a copy of the original DLL to the path you specify (typically under Program Files), will reg the DLL for COM interop, and will create the necessary reg settings. Rebuilding the Add-in project after that re-does the COM interop registration, pointing the CLSID in the reg back to your debug version of the DLL, allowing you to proceed with further development and debug. - When you create an Add-in project it sets up the debugger to launch another instance of Visual Studio in the debugger so that you can try out your add in and hit breakpoints and do debugging in the original instance you ran the debug session from. If you are working out bugs and your add-in is failing to catch all exceptions or is not unsubscribing from events, you can get some weird behaviors because your object may remain in memory in the live VS instance. If you get anything unexpected, shut down all instances of VS and re-open your Add-in solution to make sure all objects get killed and you are working with an uncorrupted instance of VS. - The code injected by the project wizard when you say you want a Tools menu item only creates that item one time, the first time your add-in is loaded. If the tools menu item is removed or exceptions get thrown in loading your add-in, you will never get your tools menu item loaded. This is because the code that creates in the OnConnection method is contained in a conditional block that checks for the enumerated value ext_ConnectMode.ext_cm_UISetup. If you want to make sure your tools menu item is recreated if it fails the first time, change this to be an || (Or) of the values ext_cm_Startup and ext_cm_AfterStartup. The downside of doing this is that there will be a minor perf hit in loading your add in because an exception will be thrown and caught when it tries to create the command if it already exists, so you may want to revert to the original check for production. But in development environments this will ensure your command gets created and is present repeatably in the face of errors and weird development startup paths. - The objects and collections in the automation object model are COM components that you are accessing through interop. In many cases to get to the underlying object and get back a valid .NET reference, you have to use the .Object property for objects and the .Item property to access items in a collection. For example, there is an ActiveWindow and ActiveDocument property on the DTE root object of the model that let you get quickly to these items in the environment. However, to get a Window reference or a Document reference variable back from these (respectively), you will need to access DTE.ActiveWindow.Object, not just DTE.ActiveWindow. Likewise, to get into a collection, you will need to index into Item with a 1-based index, such as DTE.Solution.Projects.Item(1).Object to get to the Project object for the first project in the current solution.
Monday, February 7, 2005
Testing ClickOnce Deployments
I had a question from a reader about testing ClickOnce deployments, and I thought I would pass my response along to anyone who is interested.
When you deploy a ClickOnce application, there are two manifests published with the application files to the deployment server: the deployment manifest (<appname>.application in Beta 1) and the application manifest (<appname>.exe.manifest in Beta 1). Bit of a confusing file extension choice if you ask me, but...
The deployment manifest includes information describing the deployment itself, including publisher information and a publish version that should be incremented each time you deploy a new set of files. The application manifest contains information that describes the application as a whole, including the collection of files that compose the application, and the permissions that the application requires.
When the application gets deployed to a client machine, a number of things are created at deployment. If the application publish settings are for it to only be available online, then the application files get cached under some obfuscated directories under the users profile \Documents and Settings\<username>\Local Settings\Apps. Additionally, an Application Trust will be created as part of the User Code Access Security policy for that version of the app. Finally, if the application puslishing properties are set so that application is available offline as well as online, then a Start menu shortcut and an Add/Remove Programs item is added.
The question had to do with had to do with problems they were encountering in repeatedly deploying an app to a client machine for testing. The deploy and launch mechanisms for ClickOnce are designed around the concept that the publish version should be incremented to indicate to a client machine that there is a new version to download. Although it might seem that you could just go delete the files from under the user's cache and redeploy to the same machine, you would also need to make sure all the other stuff mentioned above is also cleaned up.
There are two correct solutions to the problem of repeatedly deploying the same application to the same client machine for testing purposes.
1) Increment the publish version in the deployment manifest for each attempt. This can be done with the mage.exe tool found in the SDK bin folder. This will result in a new clean deployment to the machine each time.
2) Use a virtual machine (VMware is my preference, but VPC is fine too) in snapshot mode, where shutting down the virtual machine discards any changes made in the VM since you ran it. Now you can revert to the snapshot with a clean machine for each test.
If you test be manually deleting the files and artifacts from the user's machine, you are not testing the way ClickOnce was designed to be and should be used. In other words, you are not testing well.
Monday, January 10, 2005
Use BindingList for data bound collections
I finished up another chapter on my book last night. This one was on creating data bound custom business objects and collections. I won't try to reiterate the entire chapter here, but I will pass along one of the key take-aways: use BindingList<T> for custom business object collections if you want to provide rich data binding capabilities in Windows Forms 2.0.
The BindingList<T> generic type is defined in the System.ComponentModel.Collections.Generics namespace in Beta 1, but is getting refactored into System.ComponentModel in Beta 2. Basically this type allows you to create strongly typed collections that implement IBindingList (partially), IList, ICollection, and IEnumerable, with a single line of code:
BindingList<Customer> CustomerCollection = new BindingList<Customer>();
By doing just this, you get a collection that works fine with both Windows Forms and ASP.NET data binding mechanisms, including two-way data binding (presentation and editing) support in Windows Forms, and also will fire ListChanged events whenever items in the collection are added, removed, or replaced. If you want to support events when the contained objects are edited, you will need to implement the INotifyPropertyChanged interface on the object type definition itself (this interface is named IPropertyChanged in Beta 1).
Additionally, if you want to support sorting and searching on the collection, all it takes it to derive a class from your BindingList<T> parameterized type, and override a few base class methods and properties. For example, you could declare a Customer collection and provide searching capability with something like the following:
public class CustomerCollection : BindingList< Customer> { protected override bool SupportsSearchingCore { get { return true; } }
protected override int FindCore(PropertyDescriptor property, object key) { for (int i = 0; i < Count; i++) { Customer c = this[i]; if (property.GetValue(c) == key) { return i; } } return -1; // Not found } }
Very powerful stuff. Sorting is a little more involved, but follows the same process. Override the sort related properties, and provide a sorting algorithm in the ApplySortCore override and you are off and running.
So much easier and more powerful than the old derive from CollectionBase approach. You get type safety, alot of additional functionality, and the efficiency of generic types.
Wednesday, January 5, 2005
Selected as MVP Again
Got the email this morning dubbing me with the MVP honorific for another year. Category is still Visual Developer - ASP/ASP.NET. Very cool. I have really enjoyed being part of the MVP program for the last year. Just the opportunity to attend the MVP summit, get a free year of MSDN Universal, and some various other swag is great. There are lots of other bennies as well.
.NET | Community  Wednesday, January 5, 2005 3:39:26 PM (GMT Standard Time, UTC+00:00)  |
Sunday, January 2, 2005
Comparing the IDesign process with Agile
Roy attended a week of our IDesign Advanced .NET Master Class last week, taught (and authored) by Juval Lowy, which includes a module on our recommended approach to software development process. Roy did a great job summarizing the key points in his article here, but seemed to have picked up a little too strong of a tone on certain points than was intended, based on my knowledge of the material (from being an instructor for the class myself) and from discussions with Juval.
Specifically, in the section of his article where he talks about the differences between our process and Agile, Roy talks about the ~30% effort dedicated to architecture and makes it sound like we are recommending a big-bang, all up front, try to think of everything to do with the product before doing any construction (aka waterfall), which is not what is intended. The ~30% effort dedicated to architecture and design is in fact done up front - but done up front for each stage of the product development, which distributes that effort fairly evenly across the product development lifecycle. It is one initial up front architecture piece, where you decide on the overall architecture of the system, what the major subsystems and components will be along with their interactions, security boundaries, transactions, identities, packaging, and so on, and then a bunch of smaller architecture and design pieces associated with the specific requirements for each component or subsystem in each stage of the development.
What we don't subscribe to is the concept that you can just sit down at a keyboard and start coding and come up with a coherent design for a large scale enterprise system as you go without some up front architecture and design work. We also believe that a majority of coders do not have the experience or big picture about the product for larger systems to be making all the design decisions themselves, thus the need for a dedicated architect who makes those architecture and design decisions throughout the development (with input from the team of course).
Another point I wanted to clarify is the use of test clients. I am not a true believer (yet) in full blown TDD, mainly because of the disconnect between our approach to actually doing some design and documentation before coding, at which point the benefit of writing tests before code becomes limited. But we definitely push that you should have tests for everything, preferably written in a way that you can automate the execution of those test, at a minimum the smoke test portion of them. Those test should be written and run by the developer, and can be used by QA for their testing as well. As such NUnit style tests are perfectly acceptable for component based testing of business logic and data access components, but some things really need a UI to test them, so for those we use simple UI test clients (typically WinForms). If you have not yet adopted NUnit testing and don't want to add that to your list of technologies to conquer, then you can write your tests how ever you like (such as all little WinForms and console test clients), but you should do so in a way that is not just total throw away.
Other than those minor points, I thought Roy's article did a great job of summarizing what I know Juval taught in the class.
Saturday, January 1, 2005
Visual Studio 2005 December CTP and WinForms
I spent a little time in the last week playing with the December CTP of Visual Studio 2005. Specifically, I was hoping to use it on the chapter I was working on for my book.
The Good:
The has been a lot of refactoring going on by the Windows Client team between Beta 1 and Beta 2. Unfortunately some of that has been downscoping and removing features. A lot of stuff has been renamed as well. It looks like most of those changes are in this CTP, so if you want to see something more representative of what the RTM will look like, and a lot closer to Beta 2, then this CTP is good for that.
The Bad
This does not appear to be a very stable release from a Windows Forms development perspective. Just putting together a couple simple data binding scenarios resulted in a bunch of exceptions for things where the designer was doing all the code writing, so it wasn't a lack of understanding of the programming model on my part. So if you want to actually write any significant apps or samples in Windows Forms, I don't think you will want to do it with this CTP.
My strategy for the chapters and samples in my book is still to keep developing on Beta 1 for now, keeping in mind what is changing in Beta 2 (which can be explored with this CTP), and plan on doing a port of everything to Beta 2 as soon as it is available.
Tuesday, December 28, 2004
Amen JayBaz!
JayBaz has a great little post regarding the compulsive obsession of many programmers about worrying about micro performance differences instead of writing clean code. Similar sentiments to my thoughts on Generics performance and performance in general.
Keep in mind this is a guy who used to be on the compiler team and REALLY knows the difference in performance of various statements down at the IL level.
(Depending on how soon you read this, you may not be able to get to the post - blogs.msdn.com is down right now. Thank you RSS + Newsgator :) )
.NET | Architecture  Tuesday, December 28, 2004 11:14:31 AM (GMT Standard Time, UTC+00:00)  |
Wednesday, November 17, 2004
Generics performance concerns? Don't sweat it!
Sahil points to the #2 bug report on the MSDN Product Feedback center regarding concerns over the performance of generics. My feelings on this pretty much echo an earlier post I made about performance in general.
Who cares if generics are 1000 or 10000 times slower (which I don’t believe – it might be for first call while the type is dynamically generated and compiled if necessary, but after that the difference should be small)? What matters is whether the performance of your application as a whole is sufficient and meets your specifications. People make this mistake all the time, worrying about the overhead of every instruction, when the real performance of whole applications is usually determined by network/file/database I/O or particular computational processes. That is where you worry about performance – at the places where you have identified through measurement that it needs to be addressed. Everywhere else, do what makes the most sense for maintainable code – and the type safety and reduction of repetitive code declarations provided by generics are huge from that perspective.
Bottom line is that even if it is 1000 times slower across the board , I don’t believe that will have a significant impact on the overall performance of most apps that will use generics. You also have to be very careful about making claims like this without substantiating them with actual measurements and the situations under which the measurement was performed. I bet I can set up a loop with a generic collection and an untyped collection of value types where the generic collection would beat the pants off the non-generic collection due to all the boxing/unboxing that has to occur getting those value types in and out through object references. Does that mean that generics are XX times faster than non-generics? No, it means that in one particular scenario (which is probably an immeasurable fraction of the overall computing time of the application) there is a measurable benefit of using one approach over another.
Bottom line: Generics have huge benefit. You should plan to use them anywhere you want type safety and don't want to reinvent the wheel. If you have implemented something with them and have MEASURED that to be a bottleneck for performance in your application, then optimize that code... possibly removing the generics. But please people don't start preaching that it is a “best practice“ not to use generics because of “performance“. Ugh.
Friday, November 12, 2004
Little Rock .NET Users Group Slides and Demos
I had a great time presenting at the Little Rock .NET Users Group last night on my way back to DC from VS Connections in Vegas. I was very impressed with this group. They had a good sized crowd (30-40) in a good little meeting room that was actually inside a Pizza Hut, and are led by a great group of guys. One of the most energetic groups I have seen, and when you consider the population and industry presence in Little Rock compared to the group size, you'll realize these guys are doing a great job of running a user group! There are a lot of times we don't get many more attendees at CapArea.NET, even though we meet in the heart of the tech sector of DC.
I want to thank the group for having me out to speak and pass along the slides and demos.
Wednesday, November 10, 2004
Tuesday, November 9, 2004
Cool Tablet App - Aureole (not the nipple)
Had a spectacular dinner with my wife Robin last night at one of the swankiest (and priciest) restaurants in the Mandalay Bay hotel in Las Vegas last night. The food was outstanding (one of the top ten I can remember, and we eat out at a lot of great restaurants on travel and in DC).
The restaurant was Aureole, and one of their unique features was the four story high, four sided tower of wine that dominates the center of the restaurant. In order to get your bottle of wine, the wine steward, wearing caribiners, hooks into cables and gets hoisted up to wherever in the stack the bottle may reside.
That in itself was pretty cool, along with the great food, but what was interesting was how they manage presenting their extensive (and frequently changing) selection of wines to the customer. The wine list was brought to us as a Tablet PC running an internal web app that you could use to browse the hundreds of choices of wine, and even get additional background information on any that you are interested in. It had a bookmarking feature so that you could select any that you might be interested in as you browse the entire collection, then review your short list to make your final selection. You did all this with simple point and click with the pen.
My first thought, being a smart client zealot, was that they should have made it a smart client application. But the fact was that it was truly just a browsing app, and used a lot of graphics and animation to enhance the experience that would have been more difficult to achieve in a WinForms app.
I was just happy to see yet another powerful user experience enhanced by tablets and technology.
And the wine and food rocked.
Visual Studio Connections Las Vegas
I'm out at Visual Studio Connections in Las Vegas at the Mandalay Bay hotel and casino. Great show so far, runs through Wed. I have three talks on Wed: Synchronize Smart Client Data and Offline Data, Deploy Smart Client Applications with ClickOnce, and Introduction to .NET Deployment (Fundamentals track).
This is a great location for a conference, good hotel, lots to do and see, when you can tear yourself away from the conference facilities, which are top notch.
If you could not make this one, you should definitely consider picking up the spring 2005 show, which should be on the east coast. Keep your eyes on the site to see when it gets announced (very soon).
.NET | Speaking | Travel  Tuesday, November 9, 2004 3:23:17 PM (GMT Standard Time, UTC+00:00)  |
Saturday, October 23, 2004
Thursday, October 21, 2004
Friday, September 17, 2004
Thursday, September 16, 2004
Sunday, August 29, 2004
Reflector, what an awesome tool!
I just have to do a little spontanuous gushing on Reflector due to how extremely useful it is for me while working on my book (Building Windows Forms Data Applications with .NET 2.0). I've been chugging along, and it is going very well. However, I would be lost or taking significantly longer to get things figured out if it were not for Reflector.
I've been using Reflector off an on for a while now, but only recently started using it to figure out the Whidbey bits. It runs just fine against the .NET 2.0 bits, it just takes adding a config file to set the runtime to the .NET 2.0 Beta runtime so that it is happy. Basically, you just need the following in a Reflector.exe.config file in the app directory:
< configuration>
<startup>
<requiredRuntime version="v2.0.40607" />
</startup>
</ configuration>
Every time I come across one of those gaping holes in the Beta docs that they just haven't gotten to yet, it just requires firing up Reflector to dive into the implementation code to see exactly what a certain parameter means and how the method is going to use it.
Lutz Roeder: they should have a special community title for people like you who create tools of this caliber and usefulness, and then put them out there for free. Perhaps Microsoft Community Demi-God would be sufficient, perhaps not.
The fact that the tool is very polished and functional beyond just decompiling the IL is just very rich gravy on the steak. I especially love being able to get the Callee graph on something to see where a particular property is used or a method called from.
Thank you, Thank you, Thank you, Thank you.
Sunday, August 15, 2004
Clearing up the lingo: Whitehorse, Burton, Visual Studio Team System
A lot of people are throwing around the terms “Whitehorse”, “Burton”, “Visual Studio Team System”, “Class Designer” and others and incorrectly mixing and matching the combinations. Here is some information to help make things clear to those who might be a little confused by code-name mumbo jumbo.
Visual Studio Team System (Code-named Burton) is the family of products that will include new software development lifecycle management and design tools. There will be several product offerings in the family, targeting developers, testers, architects, and managers. Each of those will contain a different grouping of lifecycle tools, focused on their individual role in the lifecycle.
Visual Studio Team Architect (Code-named Whitehorse) is one of those products targeted at the Architect role, and contains the Service Oriented Architecture designers for modeling services and infrastructure. These tools are what are really referred to as “Whitehorse”. When you hear or say Whitehorse, you should be thinking SOA tools.
The Visual Studio Class Designer is a modeling tool that will be part of Visual Studio Standard and Professional versions, and all versions of Visual Studio Team System. The Class Designer is not part of Whitehorse. It is a feature of Visual Studio.
So just to put it in a few concise terms programmers should understand:
VSTS != Whitehorse
Class Designer != Whitehorse
VSTS == Burton
Now that we've cleared that up, I can get back to coding. Get it right, people!!!! :)
Saturday, August 14, 2004
Data Binding Scenarios??
I'm looking for suggestions for some tough data binding scenarios you have or would like to tackle in an application to use as sample cases for my book on WinForms data binding in .NET 2.0. If you have any nasty little scenarios that are not too contrived, let me know and maybe I can solve them and use them in my book.
Thanks!
Friday, August 13, 2004
Using Web Services as Data Sources in the Data Sources Window in Visual Studio 2005
The Data Sources Window in Visual Studio 2005 allows you to drag and drop data sources onto a form to generate all of the controls and components needed to use that data source for databinding. The Data Sources Window support binding to databases, Web Services, and custom objects.
The Web Services piece is still a little quirky in Beta 1 because they wisely chose to only let you bind to public properties on an object definition, not public fields. This will hopefully discourage the definition of public fields to expose data from a class, which is a bad idea all around. However, the current client proxy code that gets generated for a Web Service when you create a Web Reference just exposes public fields on the classes generated for objects returned from a Web Service. Thus the Data Sources Window in Beta 1 won't let you see any of the members on the object types returned from the Web Service.
The good news is that the wsdl.exe tool that ships with the .NET 2.0 SDK does in fact create public properties to wrap the members on the objects returned by a web service. So there is a fairly straightforward workaround to get Web Services working with the Data Sources window in Beta 1, detailed below.
1. Go through the Add Data Source wizard, select Web Reference as the type of Data Source, and point it at the WSDL URL for the data source. For example, you would point it at the Amazon Web Service at:
http://soap.amazon.com/schemas3/AmazonWebServices.wsdl
2. After completing the wizard, go check what the namespace is for the generated web procy file. To do this, you need to select Show All Files in Solution Explorer, and drill down to the Reference.cs file that was created under the Web References node for the Web Service. For the example above, that would be <YourApplicationNamespace>.com.amazon.soap.
3. Fire up a Visual Studio 2005 command prompt window, and run wsdl.exe with the wsdl url, an out param to generate the Reference.cs file, and the namespace param to set the namespace from step 2. Example:
wsdl.exe http://soap.amazon.com/schemas3/AmazonWebServices.wsdl /out:Reference.cs /n:MyApp.com.amazon.soap
4. Copy the generated Reference.cs file (or vb if that is your flavor) into the WebServices subfolder created under your project where the existing Reference.cs created by the Add Web Reference process lives, overwriting the existing file. You should see that the file sizes are about double. That is because the wsdl.exe has property wrappers for all the fields that the Add Web Reference one just exposed publicly.
5. Close the Data Sources window. Then close Visual Studio. Then reopen your project in Visual Studio 2005 and reopen the Data Sources window.
you should now be able to drill down into the properties of the data source objects returned from the web methods of the web service, and if you drag them onto a form, proper UI will be generated.
Demos from today's Windows Forms Data Binding with Data Sources in Visual Studio 2005 MSDN Webcast
Here are the demos from today's MSDN Webcast on using the Data Sources Window in Visual Studio 2005 to generate data bound UI in Windows Forms applications.
One caveat - I accidentally lied about the little demo I showed at the end that was getting album covers from the Amazon Web Service. While it is an interesting little demo, I was mixing it up with the greater project I created it for as far as the involvement of the Data Sources window. This app is actually just a simple Web Service client that takes the values returned through a data set and dynamically generates PictureBox controls to present them. The DataSources window actually has no play in this one. I included the code anyway, if you want to run it, you will have to go get a developer ID for the Amazon Web Service at http://www.amazon.com/gp/aws/landing.html. You will need to plug this in to the agent source file where it says to plug in your id here.
Demos from today's Extend ASP.NET MSDN Webcast
Thursday, August 12, 2004
UIP MSDN Webcast demosPassing Arguments when starting a task in UIP
Version 2 of the UIP application block came out back in April, and included a lot of new functionality. Unfortunately, they also broke one important capability in moving from v1 to v2: the ability to pass in an set of initialization arguments to get a task initialized.
In V1, there was an overload of the UIPManager.StartTask method that allowed you to pass in an instance of a TaskArgumentsHolder object, which itself has a placeholder TaskArguments object reference where you could stuff anything you needed to pass downstream to the task that is being launched, such as user login info, command line or querystring params, etc.
This disappeared in V2 with the move to multiple navigation models. However, the fix is pretty straightforward to get that capability back - it just involves making a minor tweak to the UIP library source code, which is not a problem since you get full source code with the block.
Basically, what you need to do is go into the Navigators folder within the UIP project, and for each navigator type you want to support arguments on, you need to change the visibility of the StartTask method that takes a TaskArgumentsHolder parameter from private to either internal or public:
public void StartTask(TaskArgumentsHolder holder) { ... }
Then go into the UIPManager class, and add an overload for each of the StartXXTask methods that takes a nav graph name and a TaskArgumentsHolder, and have it call the appropriate StartTask on the appropriate navigator:
public static void StartNavigationTask(string navGraph, TaskArgumentsHolder holder)
{
GraphNavigator navigator = new GraphNavigator(navGraph);
navigator.StartTask(holder);
}
As soon as you do that, you are back in business. You can start a task and pass in arguments with something like this:
TaskArgumentsHolder holder = new TaskArgumentsHolder(Guid.Empty,null,"startupargs"); UIPManager.StartNavigationTask("StartupParams",holder);
That's all there is to it.
Troubleshoot ClickOnce Deployment problems
A tool that many people are not aware of is MaGe - the Manifest Generator tool (mage.exe). It resides under your root Visual Studio 2005 directory SDK folder in the bin subfolder along with the rest of the .NET SDK tools.
ClickOnce deployment (.application) and application (.exe.manifest) manifest files are just XML files with a particular schema that are digitally signed with either a strong name key file (.snk by convention) or a publlisher certificate. That signing process ensures the identity of the publisher as well as making sure that the manifests are not tampered with (say to add a malicious file as part of the application download) after being published.
MaGe allows you to open, edit, and save both types of manifest files. When you save the file, it prompts you for a key file or certificate to re-sign the manifest. The tool is intended for large organizations where the deployment servers will likely be managed by IT folks that are not the developers and not running VS2005, so that they can make updates to the deployed applications and the information that goes into the manifest.
However, MaGe can also be a big help in troubleshooting and understanding your ClickOnce deployments in the development environment, especially while we are still in Beta and sometimes problems occur. One of my collegues was having a problem where he could not launch any of his ClickOnce applications after publishing. We are still trying to track down root cause, but simply opening the manifests in Mage and resaving them fixed the problem.
You saw in a previous post how you can also use MaGe to handle resigning the deployment manifest after making a manual addition to support command line arguments.
Just another good trick to have in your toolbox if you are working with ClickOnce. Hopefully this will really just be a handy tool for admins once we get to release, but for now it is pretty important for devs as well.
Tuesday, August 10, 2004
Harvesting ClickOnce Command Line Arguments
Thanks to Jamie Cool, Microsoft PM for ClickOnce, for providing the answer on a question I am often asked in talking about ClickOnce:
Question: How can I use command line parameters with a ClickOnce deployed application?
To answer that, you need several pieces of information:
1) How do you pass command line arguments to a ClickOnce application?
ClickOnce applications are launched using a URL to the deployment manifest (.application) file. So you use web querystring parameter syntax:
http://mydeploymentserver/MyApplicationFolder/MyApplication.application?param1=foo¶m2=bar
2) How do you tell ClickOnce and .NET Security to allow you to use the command line parameters?
Under the covers, you need to add a trustURLParameters=“true“ attribute to the deployment element in the .application (deployment) manifest file. In Beta 2, or at least by release, this should just be a checkbox in the poject properties Publish section. You can do this by dragging the .application file into Notepad.
You then need to open the manifest with the mage.exe tool (located in the <vstudio 8>\SDK\bin folder), and save it again, specifying a key file to re-sign the manifest. If you try to launch the app without doing this, the runtime won't do it on the client machine because it sees that the manifest has been tampered with since it was published.
Make sure to check the .application file again after signing to see if your trustURLParameters attribute is still there. If you screwed up the (case sensitive) name (as I did the first couple times), the Beta 1 mage tool will throw away any attributes it doesn't recognize when you save to re-sign the manifest.
3) How do you harvest the values passed via querystring assuming you have done 1 & 2?
string cmdLine = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0];
This will give you back the entire command line (URL with parameters), so you just need to parse that string for the ? separator between the path and the params, and then parse the remainder for the & and = separators.
Piece of cake!
ClickOnce demos from today's MSDN webcast
Monday, August 9, 2004
Digging out...
I'm not exactly what anyone would consider a frequent blogger, but it is my intent to share a few technical thoughts through this blog from time to time.
I have been dark on any real content lately other than links to demos and such because I said “Yes” about 10 times to many and have been totally buried with 8 webcasts, 4 conference talks, 4 user group talks, 6 book chapters, two product reviews, and a book technical review, all on top of full time consulting load, all in the span of July - September. So as you can guess, all that content creation and work doesn't leave a whole lot of leisure time for things like blogging. Heck, I have even stopped reading most of the blogs that I like because I flat out couldn't afford the time. Basically, my head has been about to explode for a while now, with me constantly asking myself: “why did you sign up for all this crap??“
Well, I am past most of it, at least the content creation parts of it, and plan to start blogging more to share some of the stuff I have been working on. I am spending a lot of time with the new WinForms features since that is what my book is about (due out with the release of .NET 2.0 next year), and am really digging the experience. The WinForms team has really done an awesome job with all the new stuff for building smart/rich client apps.
I've got 4 more webcasts this week that you may want to tune into if you have time:
Tuesday 10 Aug: Deploy Smart Client Applications with ClickOnce (1 PM PST)
Thursday 12 Aug: User Interface Process Application Block (1PM PST)
Friday 13 Aug: Extending ASP.NET (11 AM PST)
Friday 13 Aug: Bind Data Sources to WinForms Controls in Visual Studio 2005 (1 PM PST)
Then I am speaking at the Northampton MA .NET Architects group on 16 Aug (ASP.NET 1.1 Databinding), the NYC.NET group on 19 August (ClickOnce), and giving 4 talks at TechEd Malaysia in Kuala Lumpur 12-18 September. Then Extending ASP.NET for the DelMarva .NET Users Group in October, same for Little Rock Users group in November, and 3 talks at Visual Studio Connections in November in Las Vegas.
I love doing this stuff and teaching people how to use .NET. Too bad most of that doesn't directly earn me a cent... :)
DataGridView demos from MSDN Webcast today
Here are some simple demos I presented today in my webcast on the DataGridView control in .NET 2.0. Lots of cool new features for WinForms developers.
Kiss that obnoxious DataGrid goodbye!! There's a new grid in town, yaheer? (Yes it is still fully supported for backward compatibility!)
Monday, July 26, 2004
Visual Studio Extensibility Demos and Links from today's MSDN WebcastCMAB MSDN Webcast demos from today
Actually, just go to this post, form when I gave it recently. The demos haven't changed.
Thanks for attending!
VS 2005 Beta + VS 2003 Side by Side
Once again, Josh has pointed me towards the solution of getting Visual Studio 2005 Beta 1 running side by side with Visual Studio.NET 2003.
In this case, I had a clean Windows XP Pro + SP2 RC2 install, installed VS 2003 + all my add-ins, tools, etc., then installed VS 2005 Beta 1. Whenever trying to debug a Web app after the install, I got:
Unable to start debugging on the web server.”
In the debug window, it outputs:
Auto-attach to process '[3172] aspnet_wp.exe' on machine 'WINXPPRO-VM1' failed. Error code 0x8013134b.
The solution, found on the forums at asp.net was to simply switch the selected runtime from the new ASP.NET tab in the properties for the default web site in IIS.
Tuesday, July 13, 2004
Another reason to like Windows XP SP2
Yet another reason to love Windows XP SP2 and the advanced security measures they took in there. While everyone who has not installed SP2 RC2 yet should be scrambling to install some new security patches that came out today to cover a scary new trojan, XP SP2 express update happily announces - no updates to install.
For those of you who have not made the leap yet in fears of it screwing up your system, I've had RC2 on since it came out without incident. Better to start learning about the things that will get blocked by the security measures now (while being protected) and how to work around them than to wait until it comes out.
Sounds like the release will be next month anyway.
SP2 == good
Friday, July 9, 2004
EMAB Demos from todays MSDN Webcast
If you attended my MSDN Webcast today on the Exception Management Application Block thanks for attending! If you didn't, you suck, but can have the demos anyway. :) Just Kidding!!
Luckily I didn't pass out and my computer didn't explode from the heat since my A/C died yesterday and it is 90 degrees out and probably hotter inside right now! Off to Home Depot to buy some temporary relief until the main unit can be replaced (pronounced DOA by the service tech this morning).
Anyway, here is a link to the demo code. Let me know if you have any questions, and enjoy!
Monday, June 28, 2004
Sunday, June 27, 2004
New tools weekend
I have had a number of tools on my “to-do” list for a while now that I wanted to check out and see if they are worthwhile. Let's just say that if I had got off my ass sooner and looked at those tools, I could have easily gotten to other things on my “to-do” list much quicker. I've seen most of these mentioned in various people's blogs, which is how they made it on my list of things to check out. But it really doesn't take hold until you try them out yourself.
First newest favorite tool : CodeRush. Yes, I heard the buzz at TechEd (thanks to a lot of evangelizing by Marc Miller and Scott Hansleman, but didn't get around to checking it out until now. What can I say. WOW. So many features and capabilities, I won't enumerate them here. Just go check it out. Makes your coding experience in VS.NET a whole different (and much more productive) thing.
Next favorite: CodeSmith. Freeware code generation tool, with lots of templates and community support. Way cool. I am so done writing tedious data access, stored procedure, and business object structure code.
Yet another: X1. I blogged about Lookout lst month, which is very cool, free, and does most of what X1 does. Basically it is a google-like search engine for stuff on your machine. X1 does an even better job, working by indexing emails, files, attachments, and contacts on your machine, and making it very fast and easy to find things that I used to spend an inordinate amount of time manually hunting for on my machine. Did I put that in a file, outlook message, or contact? Well, how about answering that in seconds instead of tens of minutes.
Another cool code gen tool: RapTier. If you just want to quickly generate a data access layer for your app, or stored procedures to wrap your tables and views, or generate database documentation, this tool will get you there quick. It too (like CodeSmith) is template driven and customizable, so if you don't like the default output, it is not real hard to customize. I haven't yet decided whether I will use this more than CodeSmith. Will have to see as I use it more on some real projects.
So a few hours invested this weekend playing with new toys is going to pay off handsomely in boosting my productivity. This is one of the things I am loving more and more about the .NET community - the constant growth of capabilities and tools to make the “out-of-the-box” benefits of .NET (which are HUGE compared to other dev platforms) get dwarfed by the benefits of the things you can use in that environment to do your job better, faster, cheaper, and funner.
Saturday, June 26, 2004
Saturday, June 19, 2004
Tuesday, June 15, 2004
Sunday, June 13, 2004
Visual Studio 2003 Web Setup project uninstall debris in metabase
Visual Studio 2003 Setup and Deployment projects make it a snap to create an installer package to deploy your web app to a server and get all the files deployed and create a virtual directory in IIS. They even clean up and remove the virtual directory from IIS on uninstall.... or do they?
When you uninstall a VS created web installer using VS or the Add/Remove programs control panel, the files, folder, and vdir go away as you would expect. Unfortunately it apparently leaves some debris in the metabase for the virtual directory that sometimes creates problems for reinstalling the same application. A quick look with MetaEdit after doing an uninstall of one of these projects will reveal under the LM\W3SVC\1\ROOT that there is still vdir entries left around.
Anyone else encounter this or know a workaround, other than to first delete the vdir through IIS manager before running the uninstall? We could of course write a custom uninstall action to clean up the mess left by the VS setup project's uninstall step, but that kind of thing just makes me feel dirty all over.
Tuesday, June 8, 2004
Friday, June 4, 2004
VS 2005 MSDN Library problem - downloading pages never goes away
Had a problem with the MSDN Library for Visual Studio 2005 May Community Tech Preview (CTP) where it would just shown downloading... in the status bar forever for any topic selected.
After some googling, discovered that the readme on the MSDN VS2005 site is newer than the one on the DVD and addresses the issue:
If you use the external Help viewer with the Visual Studio 2005 Community Technology Preview May 2004, the Help system appears to be frozen when you try to access a topic. (You see the "Downloading..." message in the status bar, the progress bar barely moves, and the Internet Explorer icon continues to spin.)
Workarounds:
In the "C:\Program Files\Common Files\Microsoft Shared\help whidbey\dexplore.exe.config" file, change the following lines:
<supportedRuntime version="v2.0.40507" safemode="true"/> <requiredRuntime version="v2.0.40507" safemode="true"/>
to:
<supportedRuntime version="v2.0.40426" safemode="true"/> <requiredRuntime version="v2.0.40426" safemode="true"/>
- or -
Switch the Help settings in Visual Studio to use internal, rather than external Help. To do this, select Options from the Tools menu in either the Visual Studio IDE or the external Help viewer. In the Options window that appears, expand the Help entry and select the General subentry. In the Show Help Using dropdown list, select Internal Help Viewer. Click the OK button.
I recommend you check out the latest readme online if you are encountering any other problems since it looks like that will continue to be a living document:
http://msdn.microsoft.com/vs2005/currentreadme/default.aspx
Thursday, June 3, 2004
Extending ASP.NET MSDN Webcast demos
For those of you who joined me in the MSDN webcast today, thanks for your patience with the machine lock ups and not being able to complete the demos live for you. Hopefully the slides and discussion still made it worthwhile for you.
Here is a link to the demos that I was going to show. There are several in there and there is a readme that tells you what is there and how to get it running. If you have any problems getting it going just drop me a note or a comment to this post and I will help you out.
In case you know someone who didn't tune in and would like to be subjected to the same pain, I should be repeating this session on 13 August (and will work out the machine lock ups by then!!).
Thanks, Brian
Friday, May 28, 2004
Thursday, May 27, 2004
Microsoft Application Block focus and evolution
I led a Birds of a Feather session last night on the Microsoft Application Blocks that was pretty well attended for being the last timeslot. Most of the people there had not yet used any of the blocks, so it ended up being more of a Q&A than a discussion, but it still went well and was a lot of fun.
Today I attended a session by Wojtek Kozaczynski from the Patterns and Practices team that puts out the blocks. Very good session on the future of the blocks that I wish I had attended before my BoF. They are working on something they are calling the Application Block Library that will be released towards the end of the year. This ties together a number of the existing blocks such as data access, exception management, configuration management, caching and more into a single library that is more consistent with the architecture and interdependencies of the blocks. They are also going to add some functionality to each, improve the documentation and samples to be more consistent and well formatted, and will include an administrative tool that will plug into Visual Studio 2003 and run as an external tool to ease the configuration and management of the blocks through their underlying configuration settings. All very cool stuff.
Bottom line message was to start using the blocks available today, don't wait for the library, but for apps that get started next year you will have a will have a whole new set of blocks to work with that will be even better.
Monday, May 24, 2004
Smart client track at TechEd
Just sat in on a great session by Tim Huckaby on Architecting and Building Smart Client apps in .NET. He showed a number of demos showing the differences between web apps (even rich ones with DHTML to enhance the user experience), auto-deployed smart clients with No Touch Deployment and the AppUpdater from gotdotnet, smart device apps, and Visual Studio Tools for Office apps. If you didn't make this one, check it out on the DVDs, Tim is always an awesome speaker.
Sunday evening I sat in on Juval Lowy's smart client Birds of a Feather session. Good lively discussion on the differences and justifications for moving to a smart client and what the comparative strengths and weaknesses are.
Right now in a session on handing occasionally disconnected client applications. keeping data stored and synchronized with the back end when you do connect.
We have been talking about the merits of smart clients for some time now and steering customers in that direction whenever it makes sense. It is great to see a focus on these topics emerging at TechEd.
Tuesday, May 18, 2004
Deploying .NET Application talk at TechEd
If you are hanging out through the last day at TechEd and want to learn more about deploying .NET applications, come check out my talk DEV355 - Deploying .NET Applications. I'll be covering the basics of No Touch Deployment, and then going into detail on using Setup and Deployment projects to create MSI installers for apps of various types including WinForms apps, Web apps, Windows Services, and Enterprise Service components. I'll be showing several examples of creating custom installer classes with .NET code that you can easily plug in as custom actions in your installers to do things like create and populate databases and register and configure Enterprise Service components.
Microsoft Application Blocks BOF at TechEd
My Birds of a Feather (BOF) session for TechEd got approved. If you are interested in learning more about the Microsoft Application Blocks or share your experiences using them, come join us at 8:30 pm on Tuesday 25 May in room 14A.
ClickOnce - speaking at Bay.NET on Wed
If you are interested in learning about the future of auto-deployment of smart client applications with .NET, specifically ClickOnce (a new deployment technology in .NET 2.0), and you are in the bay area, come check out my talk this Wed night at the Bay.NET user group meeting. (www.baynetug.org).
Sunday, May 16, 2004
Windows Authentication and Authorization using Forms Auth in ASP.NET with Enterprise Services
I put together a custom authentication and authorization solution this week for a customer that I wanted to share, both because it works pretty well, and also to see if anyone can spot any gaping security holes in the approach that I didn't think of before we go prime time with it. It is basically a way to mix ASP.NET Forms Authentication with Windows Authentication and Authorization without requiring elevated privilege on the ASPNET worker process account. The solution involves using an .NET Enterprise Service (COM+) component to do the actual checks against the Windows accounts.
The scenario is this. The customer has an ASP.NET web application with some unique requirements regarding authentication and authorization. They need explicit control over the login/logout process because they need to restrict session length and number of concurrent logins for some accounts differently than others. They require that the accounts being used for auth be Windows accounts, and that the auth decisions are based on the Windows users and groups. They are also running on Win2K server. They also need to support Linux clients running Mozilla. At least they made it an easy scenario <g>.
The need for the accounts to be Windows based makes Windows auth sound like the ticket, but there was no way to satisfy the login/logout/session/concurrent login limitations in the requirements because your code is pretty much out of the loop with the built in Windows auth, so Forms auth sounds good. But then you have to use Windows account information for the actual auth decisions. Fine, that is what the LogonUser API is for.
Ah yes, but then there is that little hitch that they are running on Win2K, which requires the SE_TCB_NAME (Act as part of operating system) privilege to call LogonUser, which is not something you want to give to the ASPNET account if you want a secure system. So what to do...?
What I came up with was to create a .NET Enterprise Services component that runs in a Server application. The application is configured to run under a special Windows account that is just a normal user, but has the required SE_TCB_NAME privilege assigned to be able to call LogonUser. The account is also configured so that interactive logins are disallowed. The component exposes an Authenticate method that takes the credentials and returns a bool indicating success or failure, and returns the token that LogonUser gives you to represent the user.
The ASP.NET app includes a custom principal class that encapsulates the user identity provided by the login process through Forms authentication, and also holds onto the user token returned after calling Authenticate on the ES component. I tried using the token directly within the ASP.NET app to create a WindowsIndentity, but could not get it to work because of the token coming from another process. So I added an IsInRole method to the ES component that takes the desired role name and the user token. This method uses the token to create a WindowsIdentity and WindowsPrincipal, and calls IsInRole against that. The IsInRole method of the custom principal just calls that corresponding method in the ES component, passing in the role and the user token it cached after calling Authenticate. The user token is also stored in session so that it can be used to recreate and set the custom principal on subsequent requests.
Using this approach, the login form just calls Authenticate, and if successful, stores the user token in session and uses FormsAuthentication to issue the login session cookie. In the PreRequestHandlerExecute event handler in the application class, the custom principal is recreated and set as the principal on the context as long as the request is authenticated (managed by Forms auth). Then the rest of the app can just call IsInRole on the User property like normal, and the custom principal's implementation of that gets called. This is also the place where all the unique session length/concurrent sessions are enforced.
Obviously going cross process on every request for role checks is not such a great idea, so we also cache the authenticated roles after they have been checked once through the ES component, and time out that cache using a configurable period so that if someone's group membership has been changed and they are running a long session (the app has a self-refresh status page), those changes will be picked up.
To add some additional security, we use COM+ role based security to make it so that only the local machine ASPNET account can call into the component.
It may sound a little complicated, and it was to get it all implemented and working correctly the first time. But it has the advantage that it is very easy for the ASP.NET app to integrate, makes the custom mechanisms being used transparent to the app other than the call to Authenticate and the call to attach the custom principal. And the security provided by ES gives a way to get the privileged role out of the ASPNET process. We could have used a Windows Service to do this as well, but then we would need to call into the service somehow and protect against unauthorized callers, and all that is built into ES.
Anyone see any holes here? Was there a better way to do this that escaped me?
.NET | Architecture  Sunday, May 16, 2004 5:40:45 PM (GMT Daylight Time, UTC+01:00)  |
Friday, May 14, 2004
COM+/Enterprise Service Components are not a legacy technology
I am a firm believer in the use of component based development, and for the middle tier, Enterprise Services is the right way to go for most serious applications. Unfortunately there are a lot of misconceptions about the positioning of Enterprise Services, aka Serviced Components, aka COM+ with respect to .NET development. The biggest of these is viewing COM+ development with .NET as a legacy approach. Another is that when you build COM+ components with .NET, you are doing COM interop. Another is that COM+ is too hard to be worth it. All of these are just wrong.
To really get things in perspective, you have to think of COM+ as what it really is - component services provided by the operating system. In the same way that you use the OS for services such as file and network I/O and access control, when you use COM+, you are really just using component services provided by the OS. So doing COM+ in .NET is no more “legacy” than doing file I/O or network calls using .NET. In fact it is much less so because the level of abstraction and architecture provided by COM+ is far more advanced than those other services provided by the OS. When Microsoft put together COM+, they put together a very forward looking architecture for building robust, scalable, high performance applications.
Building Enterprise Service components is also the best thing you could be doing today to migrate to Indigo tomorrow. Most of the hype surrounding Indigo (and well, just about everything in the last couple years) is about Web Services. And yes, one of the primary scenarios for using Indigo will be to build service oriented applications that happen to communicate using web service protocols. But the thing is that the Indigo programming model abstracts away all the web service goo from you and lets you work with a much more clean and declarative model. It happens to have a declarative model that looks much closer to Enterprise Services programming today than it does to web services programming today. Through configuration, you will be able to control the transport layer and make it act like a web service, Enterprise Services, or .NET REmoting under the covers, but your code will look an awful lot like ES code from what I have seen.
So ES is not legacy by any stretch, it is very current and powerful in its capabilities, and it is very forward looking in terms of what you will build in the future.
What about interop? Well, certainly if you are calling out to a legacy COM component that is running in COM+, you are doing COM interop. But if you build a .NET ES based system, the .NET components do not use COM interop to talk to one another. There is some unmanaged code in the loop for providing those component services from the operating system such as distributed transactions, security, instance management, queuing, loosely coupled events and so on. But there is unmanaged code involved for many other things your apps do that reach outside of their own context, so you shouldn't let that fact drive your thinking about ES. Bottom line is that you need to try things and see if the technology can provide the performance needed for your application, not just blindly avoid things that you perceive to have performance penalties. And the fact is that you can get some huge performance benefits from the instance management features of COM+ and from the speed of the underlying transport if you design your system well.
Finally there is the difficulty of building ES systems. And yes, this is not the kind of technology that your average community college philosophy major can use to throw together a toy app in an afternoon. You have to design your system, consider the communications and calls between components, figure out which services you need to use and how to best use them, and you have to have a lot of discipline and automation in your development and build process to do it right. But the benefits of doing these things are huge on their own and are something you should be doing for critical business applications in the first place, whether you use ES or technology X.
You also have to consider the time/cost payback of using ready-to-use, well tested and proven technology for services like distributed transactions, authentication and authorization at the application, component, interface, and method level, object pooling, just in time activation, queued component method calls, etc. etc. Sure you can build your own mechanisms for these things, but are you really so vain as to think you can build it better than they did? And without spending orders of magnitude more time than it would take to use the services out of the box? Need 2, 10, or a 100 components that call each other, possibly touching many different databases, to all become part of one distributed transaction? Sure thing, just slap an attribute on each class and each public method and you are done with ES. How long would it take you to get this right managing the transactions yourself? A little longer methinks. A security mechanism that can be locked down by the developer with a few attributes at design time based on the spec, but that can be easily modified later on adminstratively if requirements change? Done with ES. Spin your own? Have fun. Dispatch method calls asynchronously through MSMQ to components that you may not even have network access to at the time you execute? Sure thing, with ES a couple attribute, a slightly different instance creation coding pattern, done. Spin your own? Have fun.
Bottom line, people need to get past the fear and misconceptions of Enterprise Service components. If you are building toy apps, go ahead and ignore ES and keep building monolithic or client-server apps that don't scale and are hard to maintain. But if you are building serious business apps for the middle tier and might need any of the services mentioned, then you should be looking at ES as one of your first choices. ES is an incredibly powerful capability that too many companies dismiss out of hand.
If you want to learn more, first, pick up a copy of Juval's book. A strategic .NET-only developer will read every chapter for the concepts and understanding of each of the COM+ services, but will not get wrapped up in the C++ code presented. They will then cross reference the appropriate portion of Chapter 10, which presents just how to use each service with Enterprise Services in .NET.
Also, check out our IDesign Method, which is one of our service offerings for helping companies architect and design their ES systems.
Saturday, May 8, 2004
Address perf WHERE IT IS NEEDED
I sat in a talk recently on performance with .NET applications. The speaker was suggesting things that I here others say often but I strongly disagree with. Two specific issues were the recommendation to use ngen and to never include debug info in release builds to achieve the best performance. The conversation went something like this:
I pressed him on the ngen:
Me: I thought one of the reasons you shouldn’t ngen is because the JIT compiler can do optimizations that result in superior runtime performance over ngen?
Him: Well, yes that is true
Me: So if you really care about perf, you shouldn’t ngen?
Him: Yes, but if you ngen you dramatically improve the start up time for the app
Me For the first time the app is run only, right?
Him: Well, yeah….
Me: And, there are load time effects that ngen can have (rebasing) that can actually result in worse load time perf?
Him: Well, yeah…
Then the debug info in release mode:
Him: You should definitely avoid putting debug info in your release builds
Me: So what is the impact if you do?
Him: Well, a couple extra instructions per method call
Me: So do you think an extra couple instructions actually has an impact on the overall perf of most apps? Aren’t they usually IO bound or have other perf bottlenecks that really form the performance limit for most apps?
Him: Well, yeah…
Why don’t people get this? I'm not saying you shouldn't always consider perf or that you should do stupid things that will affect perf. But if you are doing things that affect the maintainability of your system, I would always favor doing the things that result in more maintainable systems. Then address perf where needed. If your performance is already adequate, then you don't have a problem. If it is not, it is probably due to one or a couple hot spots in your application that you can do some optimization on to get things back in check.
Ngen can either help or hurt perf, and can result in unpredictable results if anything in your system changes with respect to what version gets used. Me, I like deterministic systems. Debug info in your release builds can give you additional insight when errors happen in the production environment including line numbers in exceptions and additional ways to debug.
A lot of it has to do with good architecture and design too. Most often people apply performance tweaks liberally because they have no idea where the hot spots might be in their app or how to find them.
I just get frustrated when people latch onto a concept and apply it blindly without understanding when/where it is actually needed. Let's face it, if a couple extra instructions per method call is really driving the performance of your entire application, you either write some incredibly tight code, or your app is a simple little test app that you created to drive home your point that doesn't go out and make any DB queries, network calls, access the disk, or any of the other things that really drive the perf of real world apps.
.NET | Architecture  Saturday, May 8, 2004 3:32:20 PM (GMT Daylight Time, UTC+01:00)  |
Friday, May 7, 2004
Whidbey toys
I got to spend a week in Redmond this week playing with some of the new stuff coming in Whidbey, using newer bits than the Community Tech Preview represents. Very cool stuff. Feels like being set free in a toy store's developmental lab to play. Tom Hanks on geek toys.
The Windows Client team has been doing their homework and you will be very pleased if you are a WinForms developer. Unfortunately I can't say much more than that. But you should be waiting with breathless anticipation with your trembling, twitching finger hovering over the mouse button to click that download link when Beta 1 first becomes available.
It was a good opportunity to provide some feedback based on the customers I deal with and the devs I teach through classes and speaking with INETA. It was also a great week for figuring out what the right things to cover and highlight are in my upcoming book with Addison-Wesley on Building Windows Forms Data Applications.
Next week I spend a rare full week at home befor hitting the road again.
BTW - if you are a steak lover and are in Seattle - you owe it to yourself to go to Union Square Grill. F%*cking fantabulous.
.NET | Community  Friday, May 7, 2004 5:50:37 AM (GMT Daylight Time, UTC+01:00)  |
Thursday, May 6, 2004
Yet another side-by-side VS 2003 - 2005 installation
Installed VS 2003 and 2005 side by side again and had to do the treasure hunt through google to find all the little fixes to get it all working again, so thought I would consolidate them here.
After installing both:
1) Fix the registry keys so that IIS manager works again.
2) Unregister aspnet_isapi.dll in the v2.0.40301 directory under windows\microsoft.net with regsvr32 -u.
3) Re-register aspnet_isapi.dll in the v1.1.4322 direcoty with regsvr32.
4) Re-install iis from v1.1.4322 with aspnet_regiis -i
5) Reset IIS with iisreset.
After that, life was good with IIS, IIS management, VS web project creation and debugging.
Sunday, April 25, 2004
PInvoke.net - what a great idea
Duncan points to a site created by Nathan that is a Wiki of Pinvoke signatures, tips, and tricks. What a great idea. When I teach people about PInvoke, I usually make the comment that one of the trickiest parts of getting it right is getting the signature mapped correctly from the unmanaged types to the managed types. That and of course creating the objects properly and passing them as parameters and handing them as return values. This site will make a great resource for dealing with some of those APIs as long as it continues to grow.
I will make it a point to go add stuff there every time I find myself making a PInvoke call that is not already fully documented there. You should too!
.NET | Community  Sunday, April 25, 2004 8:46:03 PM (GMT Daylight Time, UTC+01:00)  |
Tuesday, April 13, 2004
Hosting multiple communities with the ASP.NET Community Starter Kit
I had a reader of my article ping me today because he was having a hard time finding good concise help on how to set up two (or more) communities in an installation of the Community Starter Kit. Rather than just share it with one, I figured my blog is the perfect medium to share it with many. My response is below.
---
The kit is definitely capable of hosting multiple communities or virtual sites out of a single installation. Basically what it does is it discriminates a different “site” based on the server name used to address it. So to host multiple sites, you will need to have multiple domain names mapped to your server, or be able to discriminate them by subdomain (i.e. the servername in servername.domainname.org). Lets say you want to host ClubAAA and ClubBBB as distinct sites from a single installation. ClubAAA and ClubBBB will have to each have their own domain name or subdomain name, mapped to your server. Then when users come into http://clubaaa.org/default.aspx they see one site, and when they come in to http://clubbbb.org/default.aspx, they see another site, even though those two domain names are mapped to the same virtual directory in IIS, the directory where the CSK was installed. Or they could come in as http://clubaaa.hostingdomain.org and http://clubbbb.hostingdomain.org and those two could be mapped to the same installation folder in IIS.
Within the kit, you create two communities using the ISPAdmin interface, which will be at http://localhost/CommmunityStarterKit/ISPAdmin/default.aspx with a default installation. The key thing is to have the domain or subdomain names different. You can play around with this by adding a second community on the local machine. Have one of the communities mapped to a primary and community domain of localhost, and have the second mapped to a primary and community domain of 127.0.0.1. Because the server name part of the URL will be different when you address these two ways, the kit will see them as distinct domains and thus they can be used to discriminate different communities.
You can then go tweak the settings for one domain’s appearance to immediately see the effect. Log into the first community (http://localhost/CommunityStarterKit/default.aspx) with the admin name and password, and go to the Admin interface. Select the Edit Sections option, and select the Appearance tab at the top. Change the theme and style to a different named theme than the default Lunar one. Save the changes and return to the site. You should see a different theme. Now change the address in the URL of the browser to http://127.0.0.1/CommunityStarterKit/default.aspx and you should see the old theme.
Once you have multiple communities set up like this, any changes made to one site or the other through its admin interface will be partitioned by the settings that get saved in the database based on the server name in the URL that you are using to access the site. Likewise any changes made to the site’s data (events, downloads, discussions, etc.) will be partitioned as well from a presentation perspective. In the DB itself, the data all lives in one set of tables intermixed. But the data is always linked to the community to which it belongs so that when it is rendered out through the engine to the UI, it looks to the user like they are accessing a separate physical site.
Thursday, April 8, 2004
VS 2005 CTP IIS problems fixed!
Thanks much to Josh for pointing me here which pointed here which gave the magic incantations and voodoo hex remover to fix the problem I was seeing with IIS after install of VS 2005 CTP.
Sunday, March 28, 2004
Side by Side VS.NET 2003 and 2005 CTP
Just for grins, I tried installing VS.NET 2003 and VS.NET 2005 CTP side by side in a virtual machine. I was pleasantly surprised with the results. They both installed fine and seem to run well on their own. Haven't tried any heavy development with either yet, so the true verdict is still out.
Of course, the problem noted in my previous post about IIS management console being broken is even more pronounced in this configuration, because you can't run the integrated debugger for web projects either. You will get an error that says VS can't launch the debugger. I was still able to run the web app and attach the debugger manually though.
Obviously not a recommended approach for a production development box, especially if you are developing web apps, but it was still a much more seamless attempt than when I tried the same with the PDC bits.
VS.NET 2005 CTP Breaks IIS
Found an unfortunate little side effect of installing the Community Technical Preview (CTP) of Visual Studio.NET 2005 (Whidbey) - IIS management console goes stupid and can no longer display properties of web sites. Good thing Whidbey no longer uses IIS for debugging on the local machine...
Saturday, March 27, 2004
VS.NET 2005 Tech Preview 2 Install Complete
I got VS.NET 2005 Tech Preview installed easily. The only hitch - you have to remove the 1.2 version of the framework that the previous tech preview installed.... and Yukon depends on that version of the framework. Hmmm. So no more working with Yukon until they come out with another beta?
Sunday, March 21, 2004
Code Expansion in VS.NET Whidbey - Good as QuickCode.NET?
I've been a big fan of QuickCode.NET since it first came out. At $29 a pop, well worth it for the amount of typing it saves me when coding. I have code expansion templates defined for common/tedious tasks such as defining type safe collection classes, adding event accessors to classes to encapsulate event members in C#, and even simple starter chunks of code like adding the block of code to declare an OpenFileDialog and check the return result before accessing the FileName property. I'd much rather type about 10 characters to do that than several lines of code, even with intellisense to help out with each of those lines.
For example, with QuickCode and one of my templates, I can type the following:
coll CustomerALT-Q
and I get a fully implemented type safe collection class with all the Add, Remove, IndexOf, Indexer, etc. members defined on it to only take Customer objects and store them through the CollectionBase class.
Likewise I can type
evtacc EventHandler MyEventALT-Q
And I get a member delegate of type EventHandler and a C# event accessor encapsulating it properly and exposing it as an event named MyEvent.
QuickCode has a nice little editor and runs within VS.NET as an Add-in, and lets you manage the individual templates and copy them to the clipboard as XML and import them from an XML file. You can also add modifiers to the template to help with camel or Pascal casing the emitted variables. All very sweet and easy to work with.
If you use QuickCode.NET and want me to send these to you by the way, just send me an email at brian.noyes@idesign.net.
Now (unfortunately for the vendor of that product), there will be Code Expansion as part of the refactoring support in VS.NET Whidbey. I like the idea of having it integrated with the other refactoring features in Whidbey, and it will be extensible to allow you to define your own expansions through XML files.
I haven't had a chance to use the code expansions a lot in Whidbey yet, and don't know what the final UI will be like for activating them and defining custom templates. Right now the templates all sit in a single XML file down under the VC#\ExTemplates folder, and as far as I can tell, there is no UI for defining your own. I don't know if this will change. If not, I guess the third party vendors still have an opportunity to add value by providing a nice UI for editing the templates and maybe import and export them for backup purposes (which I have found very important with QuickCode for when I rebuild my machine - a regular occurrence).
On one hand I like it when features like this are incorporated into VS.NET because I don't have to go locate and buy a bunch of additional tools once the product comes out to become fully productive in the environment. On the other hand, it is a little bit of a shame to see nice little niche's that vendors have filled with a product evaporate from under them.
As long as the implementation in VS.NET is as good or better, I'll be happy in the long run. But the jury is still out until I see what the final surrounding support set is.
Wednesday, March 17, 2004
Prefer XPathNavigator
I spoke last night at the Central Pennsylvania Users Group in Harrisburg, PA. They have a great group and about 35 folks turned out despite snow and nasty weather. Judy Calla is the group lead and gave a nice little beginners talk on debugging and error handling in .NET applications. I then jumped in with a talk on querying XML data in .NET.
One of the key points I always try to draw out in that talk is to get people familiar with the XPathNavigator model and the differences between the various types of XML documents in .NET (XmlDocument, XmlDataDocument, XPathDocument).
It is a natural fit for people who have worked with MSXML before to settle in and use the XmlDocument class (the W3C DOM implementation in .NET), never going beyond the methods and properties exposed by XmlNode and its derived classes to do their work.
However, I try to get people familiar with the fact that the preferred model for working with XML data in memory in .NET is working through the XPathNavigator, since it can be used across all three of the document types, and especially since it will take on an even more significant role in .NET 2.0 with the introduction of the modifiable XPathDocument. More on that in a minute. I also point out that you can layer an XPathNavigator implementation on top of any hierarchical data that you control, giving it an XML like working model, even though it may have nothing to do with XML itself.
The XPathNavigator base class ( and the concrete implementations provided by each of the document types) provides a consistent and clean model for navigating and querying XML data. To get one, you just call CreateNavigator on the underlying document instance. What you get back is effectively a cursor into the document nodes that you can move around with the various MoveXXX methods, or you can query the current node and all sub-nodes with XPath expressions. When you query through this model, you have the choice of just passing an XPath expression as a string to the Select or Evaluate method (the former returns a node set result, the latter returns a value result - bool, number, string - if that is what the XPath expression is expected to evaluate to), or you can pre-compile the expression for faster execution if the query will be made more than once.
The XPathDocument class in .NET 1.X is a lighterweight object model than the one in the XmlDocument class and will have less of a footprint in memory for the same XML document in most cases. The big decision point in which of those two document types to pick currently is whether you need write access to the nodes you are dealing with. If the answer is yes, you only have one choice currently, and that is to work with the XmlDocument class. You can and still should do so through an XPathNavigator, but the underlying nodes are still XmlNodes instead of XPathNodes, and are therefore write access. If you are just looking to query and navigate the data to perform processing, then XPathDocument is the better choice because of the lighter weight object model.
In .NET 2.0, the big thing to be aware of is that the XPathDocument class becomes read/write. But more important than that is that any changes you make to the document (modifying, inserting, or deleting nodes) are tracked by the document in a similar fashion to the way the DataSet tracks changes. This means that you can then use the XPathDocument to perform updates to the underlying data store from whence it came. That is huge.
So bottom line, if you are not using XPathNavigator today for working with your XML documents in .NET, you should be. Look into and get used to the model. It will give you better consistency and a migration path to move you XML document processing code from the DOM today to the XPathDocument in .NET 2.0 with minimal changes.
Saturday, February 28, 2004
Returning typed data sets from a web service
For my DataStream column in asp.netNOW, I happened to pick the subject topic for the installment I turned in Monday and that should go out any day. Then I see this post from Kirk. Damn, I hate when people come up with better solutions that me, especially when I just published mine in a widespread form.
The solution I wrote about is to simply merge the data into an instance of the common typed data set type from the web service proxy created typed data set. Works fine, but has the overhead of copying over all the data.
With Kirk's solution, no copying. Cool.
Thursday, February 26, 2004
Back from Chicago for a few days
I have been in Chicago for the past few days teaching a tailored version of our .NET Master Class to an investment company who is heavily vested in FoxPro development but are making the leap to C# and .NET for the future. Good for them!! They have seen the light and are now well educated to follow it. I'm going back for two more groups of devs for the same company in the next few weeks.
I love teaching .NET to groups like this because it really teaches me a lot seeing how devs with completely different backgrounds adapt to and adopt .NET, and I love seeing their excitement at getting to take on such a cool new development experience.
Friday, February 20, 2004
Finding File info with WMI in managed code
When WinFS comes around life will be much improved with respect to obtaining information about files stored on your system. For now, there is a mishmash of things you have to do depending on what information you are going after. If you need basic file attributes, you use the FileInfo object. If you need information about the content, you will usually have to open the file and do some form of parsing. If you want security related information, you will have to go through either a Win32 API or WMI in many cases.
I had someone at the Richmond.NET group I spoke at last night come to me with what seemed like a simple question: How do I get the owner of a file? My first reaction was that it should be part of the file attributes accessible through the FileInfo object, but that was not the case. A little digging revealed that particular piece of information is treated as part of the security information associated with a file in NTFS, and would not be available in Win98/Me.
Next look was at the Win32 APIs, and sure enough there is a fairly straightforward way through the GetSecurityInfo API, but that meant doing a lot of PInvoke interop, which I like to avoid if at all possible. It occurred to me that WMI probably had a way in, and that led me to a easy solution posted on the Experts Exchange site by “The Learned One”.
Here is a distilled version of what he presented, in C# instead of his VB.NET:
private string GetFileOwner(string path)
{
ManagementObject mgmt = new ManagementObject("Win32_LogicalFileSecuritySetting.path='" + path + "'");
ManagementBaseObject secDesc = mgmt.InvokeMethod("GetSecurityDescriptor",null,null);
ManagementBaseObject descriptor = secDesc.Properties["Descriptor"].Value as ManagementBaseObject;
ManagementBaseObject owner = descriptor.Properties["Owner"].Value as ManagementBaseObject;
return owner.Properties["Domain"].Value.ToString() + "\\" + owner.Properties["Name"].Value.ToString();
}
The key to working with WMI is figuring out the right objects, methods, and properties to access. Once you get used to the hierarchical approach of the object model, it is fairly easy to thread your way through and find what you need in the WMI documentation, and then translate that into System.Management class calls you need to make.
Keep in mind that many of the things you can do with WMI require administrative privilege. If you are expecting people to be able to use your app as non-admins, make sure you test it out to make sure the things you are doing are not privileged operations. In the case of the queries above, you can just be a standard user account in windows running this code and it works fine.
Saturday, February 14, 2004
Week in Redmond
I got to attend a design review of some stuff I can't talk about in Redmond this week. Suffice it to say there is a lot of really cool stuff coming down the pike in the Whidbey time frame, a lot of which people have not even heard about yet.
I am always impressed by the size of the campus, the energy and activity when I am there. The project managers and program managers we deal with are all very enthusiastic and motivated about their jobs and really just busting their butts to pump out good tools to make our lives as developers better, easier, faster.
People can bash Microsoft all they want, but my respect for them as a company and as a group of individuals just grows the more direct contact I have with them.
.NET | Community  Saturday, February 14, 2004 3:03:28 PM (GMT Standard Time, UTC+00:00)  |
Saturday, January 31, 2004
Help shape content for asp.netPRO
As many people know, I am privileged to be part of the editorial board for asp.netPRO magazine. Now and then the board puts their heads together and tries to predict what good content topics would be for the next 6 months or so, both feature articles, and whether we need to modify our column focus.
If you are a reader of asp.netPRO (or maybe more importantly, WOULD be a reader of asp.netPRO if it did XXXXX), please let me know any ideas you have for things you would like to see in the magazine. We can never manage to tickle everyone's fancy, but we do like to get as much input as possible and try to find the best mix we can.
Probably the hardest thing to deal with is balancing the mix of future technology (i.e. .NET 2.0, Yukon, Longhorn, etc.) material - which is the sexiest and most attention grabbing stuff, with the current technologies, the stuff you need to build your ASP.NET web apps today.
So if you have any ideas for feature articles, new columns, etc., I'd like to hear them. Drop me a note in the comments, and if it requires follow up, I'll track you down.
This is your chance to make asp.netPRO a better magazine for the community at large, as well as for yourself.
.NET | Community  Saturday, January 31, 2004 1:55:54 AM (GMT Standard Time, UTC+00:00)  |
Tuesday, January 27, 2004
Monday, January 26, 2004
My .NET Rocks! Show is online
That moment of trepidation is past. My .NET Rocks! interview is live, and I think it came out pretty well. Checked it out this morning, and at least there was nothing where I was horrified by the way I answered or came across in the end product.
There were of course a number of things that I felt I could have explained better, most of which I thought of 5 minutes after we were done taping, but that is standard for any live unscripted thing like .NET Rocks! In fact, I think that is one of the things I enjoy about .NET Rocks! as a listener, is the fact that it is unscripted, so the conversatioon can take many unexpected turns.
The one “duh, stupid” that I thought of right after the discussion was the question on remoting and had I been looking at what was new there in Whidbey... you would think the Indigo workshop I attended in Redmond a few months ago would have jogged my memory as to what the remoting story is in Whidbey... it's called Inidigo, and its not part of Whidbey. They are not going to invest any time enhancing or modifying a remote communications protocol that will be subsumed by Indigo a year or so later. Oh, well, those thinking on my feet marks go down a little on that one.
Anyway, it was a cool experience to get on the show, especially since it is getting so big and well known. Thanks to Carl for having me on, and I'll enjoy listening to Carl and Rory on all the future shows.
Carl: Great idea on the live show this Friday, but make sure to tape it still for us offline listeners!
Friday, January 23, 2004
Web based training resources
I am a big fan of getting a little extra knowledge squeezed in wherever I can find time. I always take tech books or magazines with me when I am sweating my fat ass off on the cardio machines at the gym, and any time I have where I can't have my hands on a keyboard coding or writing, I still want to be absorbing knowledge to try and stay up with the flood in our business.
The amount of audio/video stuff available now is awesome. First choice is often .NET Rocks!, which I recently interviewed on and should post next week. This is great conversational coverage of all kinds of topics on .NET development with many of the top names in the industry on there. And occasionally a nobody like me...
MSDN has been blossoming with resources as well. Between the .NET Show, MSDN TV, and Webcasts, there is no shortage of materials there. As Kirk points out, having webcasts available on demand is a big plus for a busy schedule.
My one beef with webcasts is this: make them available for download again PLEASE! Up until 1 November, they were using a tool called Interwise for the webcasts that was a plug in to IE. The links allowed you to view them online in a streaming format or right click/download the vcm files, in which case you could watch/listen offline. Now they have switched with Windows Media Player streams, which is great, but a download option is still needed.
Now I don't have time to sit staring at the screen for hours a day, but I do unfortunately have to waste hours a day on the road, or when I am not in town, on a plane/train/etc. I obviously don't watch when I drive, but I do like to be able to play the audio of the webcasts while commuting. You miss some stuff not being able to watch the screen, but when they are just talking to slides the real content is in the audio.
Another great source to be aware of are the DVD sets from the major Microsoft conferences. I got the set from TechEd and PDC. The TechEd ones were a mix of recorded talks and just slides, but for PDC they have almost every talk on there in a format that you can play with audio in IE. Now all those tons of sessions I wanted to go to but couldn't I get to hear after all. Hopefully other conferences will be able to start putting out DVDs of this quality with their content as well, but I'm sure there is a bit of a budgetary issue there given the financial stability of some conferences' promoters.
Thursday, January 22, 2004
XmlSerialization and Interface Based Programming
Check out the code below and see if you can see spot what is wrong with it:
public interface IChildObject { string Name {get;set;} }
public interface IContainerObject { IChildObject Child {get;set;} void Save(string fileName); }
public class ChildObj : IChildObject { private string m_name = "Fred"; public string Name { get { return m_name; } set { m_name = value; } } }
public class ContainerObj : IContainerObject { private ChildObj m_child = new ChildObj(); public void Save(string fileName) { XmlSerializer xs = new XmlSerializer(typeof(ContainerObj)); FileStream fs = File.OpenWrite(fileName); xs.Serialize(fs,this); }
public IChildObject Child { get { return m_child; } set { m_child = value as ChildObj; } } }
This was one of those subtle little things that was confounding a customer new to .NET, but the not so descriptive exception made it a little easier to figure out once I saw it:
InvalidOperationException: There was an error reflecting the type ContainerObj.
The issue of course is that XmlSerialization uses reflection to figure out what to write out. It probes the type and gets all its public fields and properties and writes those out with serialize or reads them in with deserialize. Because the container object exposed its child property as an interface type instead of the implementation type, the reflection stopped there and choked and it can't XML Serialize this type.
If it is already using reflection, why couldn't it have been coded to use reflection a little harder and determine the underlying type for any interface properties? There are a lot of situations it would be good to expose the property as an interface instead of a concrete type, but if you do that, you can no longer benefit from the simple XML serialization mechanism. I hate to have to violate good interface-based design just to take advantage of XML Serialization, but it seems like that is the only choice here.
I realize we could use normal .NET serialization (binary or SOAP), but XmlSerialization was ideal for the task at hand.
Hopefully the changes they are making to XML Serialization for Indigo will make this scenario OK.
Am I missing anything obvious?
.NET | Architecture  Thursday, January 22, 2004 1:54:06 AM (GMT Standard Time, UTC+00:00)  | .NET Training Days in DC and NYC
If you happen to be a reader and near DC or NYC and want some great training dirt cheap, I'm giving some .NET Training days on 3 Feb in DC and 30 Mar in NYC. The DC one is a full day of C# and .NET Framework fundamentals, and the NYC one is focused on exploiting the security mechanisms in .NET for Code Access Security, role-based security, ASP.NET authentication mechanisms and so on.
Shameless marketing plug, sorry...
Wednesday, January 21, 2004
Spoke at MAVBUG
Tonight I spoke at a small users group in Millersville Maryland, the Maryland VB and Access User Group (MAVBUG). This was a bit of an odd one because:
1) I didn't know about the group or that I was going to speak at it until less than 48 hours prior (I was again pinch hitting on short notice, this time to help out a speaker who had a travel conflict out of his control).
2) This group was not a .NET Users Group and had not even heard of INETA (Gasp!). I made a good sales pitch, so hopefully they will join.
3) The fun part: Due to a group lead who was incommunicado until I showed up at the meeting, I had no idea what topic I was going to talk on until 5 mintues before the meething.
Luckily I had 5-6 talks ready to go that I have given to other .NET User Groups through INETA, and the group lead was glad to be able to pick one of several. But it was still a bit of a challenge to mentally prep in 5 minutes for a talk I hadn't given in over 6 months. Then to add to the scramble, the group lead expressed grave concern about presenting the code in C# to a bunch of VB guys who really are not focusing on .NET at all yet (Yeah, I harped on the train leaving the station a little bit there too).
So in addition to trying to review the slides quickly, I also had to quickly convert 7 demo projects from C# to VB.NET. Thank god for an awesome little VS.NET Add-in by Jon Rauschenberger that was once on the MSDN site but seems to have disappeared.
The talk actually went very well, especially given the circumstances. But they also picked one of my favorite topics, .NET Data Access, so it was basically an easy day for me to give an intro level talk on ADO.NET.
As always, I enjoyed the opportunity to get out and talk about .NET, meet developers with different experiences and concerns and learn from what they are focusing on. I am still amazed how many developers and companies are doing zero .NET and still in the mode of trying to decide when they will start to take a look at it. How do we get the message out there any better about how much better life with .NET is?
Friday, January 9, 2004
Microsoft Application Blocks Article up on asp.netPRO site
My article on the Microsoft Application Blocks is now live on the asp.netPRO site. Unfortunately for some, you have to be a subscriber to access it. It will be in the next print mag that comes out as well.
The article covers the blocks at a high level, then drills down into the DAAB and the UIP blocks. I have other articles on the site for the CMAB block and have one on the EMAB coming out soon online as well. These latter two are not locked to subscribers only.
.NET | Architecture  Friday, January 9, 2004 6:32:22 PM (GMT Standard Time, UTC+00:00)  |
Tuesday, January 6, 2004
Done taping .NET Rocks!
Carl Franklin was kind enough to invite me to interview on .NET Rocks! and we just finished taping. I was a little nervous knowing the size the show's audience has grown to, being a dedicated listener myself. But Carl is a master at doing these things and just made it feel like a good techie geek conversation between friends.
We focused mainly on ClickOnce, which is one of the things I have been spending most of my time focusing on in Whidbey, and covered all the things that make ClickOnce a great thing. I also got to brag a little on what I used to do, and put a plug in for my book.
You just can't buy good publicity like that. Unless I sucked....? :P
Should be up on the site in a few weeks.
Thanks Carl!!
.NET | Architecture  Tuesday, January 6, 2004 8:25:08 PM (GMT Standard Time, UTC+00:00)  | Starting a new book
Just signed a contract with Addison-Wesley to write a book on building data-driven Windows Forms applications with .NET 2.0. Main focus will be on all the new data-bound controls in WinForms 2.0. Lots of really cool stuff there to talk about.
With that and my asp.netNOW DataStream column, my Data and Desktop column in C#Pro, and one other possible book project, I think it is going to be a busy year of writing.
Maybe I should go off to Cayman for a few months to focus... Yeah, that's the ticket. Not make any money consulting, make nothing for one column, little for the other, and maybe someday make a few bucks from the book... sounds like a winning business plan to me.
Should be fun though, I'm looking forward to the experience and hope to deliver the definitive story on data binding for rich client apps in .NET 2.0.
If you have ideas of things you think will be key aspects to cover, please let me know. You might expect to see some posting in the future having something to do with the topic...
Wednesday, December 24, 2003
Never say Never - why extensibility is a good thing
I had one of those great “I told you so” moments with a consulting customer today. About a month ago, I recommended using the Exception Management Application Block (EMAB) for publishing their exceptions because of the ease of use and extensibility it offered. If you are unfamiliar, the EMAB lets you publish exception information in a catch block to any number of publishers with a single line of code:
catch (Exception ex) { ExceptionManager.Publish(ex); }
Through the config file, you can then wire up zero to many publishers such as the built in Windows Event Log publisher, an XML file, a database, email, and so on. You can modify where the exception information gets published anytime without changing anything but the config file. You can create your own custom publishers and plug them in very easily as well.
So what I had proposed was to create a custom publisher that would log any exceptions to their existing application event log, which is just a SQL Server table that their monitor application accesses, with all the details that come along with the exception (message, stack trace, target, user, date time, etc.). The customer balked because they were intimidated by the block and thought it was too complex for their needs. “We never need to publish anywhere except our event log, and we already have code that does that”. Uh-huh, sure. Never huh?
Today the customer stumbled down a dark and windy road of synchronization nightmares due most likely to a shared data object class that was being hammered on by multiple threads and didn't have complete and safe synchronized access to its members. “Everything worked great in debug mode, but when we run in release mode, it blows up right away with a null reference exception.”
Oh great, I love these. Where is it blowing up exactly, I asked? “We don't know, we didn't have room in the database fields for the full stack trace, so we just left that out.” Mmm. OK. Brute force time. Lets insert a trace statement in the exception handler to dump the context so we can see what is going on. Oh goody, just inserting trace statements in the method where it is occuring makes the problem go away. Surely no race condition here.
Then the customer ponders - “how can we get more information out about the exception if the exception goes away when we add more code to dump it?” Exactly. Wouldn't it be nice to just wire up a different publisher right now that can dump the full exception - type, message, stack trace, etc. - to an XML file or somewhere else for analysis without having to modify the code. Why yes it would.
Extensibility is your friend, especially when someone else (thank you Microsoft) has implemented it for you. I am absolutely against speculative design. But you also have to be realistic about things that might need to change after you ship and make allowances for them. If there are things you can use like the Exception Management Application Block, or any of the other applications blocks that give you an extensible design that just requires a little extra up front complexity to integrate, think seriously about what it might buy you down the road. We probably could have tracked down the exact cause of the problem today quickly if we just had complete information about the exception. And that information could have been easily obtained, even in release mode, without changing a line of code, if they had used the EMAB instead of a home grown, non-extensible solution.
Friday, December 19, 2003
Don't try this at home - ways to kill a Friday afternoon
Well, it was worth a shot...
I thought to myself, “gee, I'm spending a lot of time working with Whidbey, wouldn't it be nice not to have to fire up a VM every time I want to try something out in Whidbey?”. Encouraged by some posts by some apparently more lucky people than I who claim to have successfully installed VS.NET Whidbey and VS.NET 2003 on the same machine, I decided to give it a try.
So now I am spending the afternoon trying to get my tablet back to a stable .NET 1.1 development platform.
Oh well, what did I expect. Its an alpha that says it is not compatible for side by side installation with 2003. Maybe when Beta 1 comes out. For now VMWare is my friend. Maybe Virtual PC 2004 will become my friend if it performs better than the Connectix version.
Tuesday, November 25, 2003
Misconceptions about ClickOnce, BITS
I've heard several people talking or writing about ClickOnce and there seem to be some common misconceptions arising.
First: ClickOnce is a .NET Framework 2.0 (Whidbey) feature, not a Longhorn feature. There will be enhancements introduced by Longhorn that make it even better, but the core functionality is provided by the .NET 2.0 runtime, some classes in the framework, and Visual Studio Whidbey support for publishing and configuring ClickOnce apps.
Second: BITS (Background Intelligent Transfer Service) is not currently planned to be supported in the Whidbey release as far as I know. That is one of the big enhancements that Longhorn will bring. There will be support in Whidbey for trickle download of assemblies as they are used (although this is not in the PDC alpha version), but it will be a straight download, not using the BITS service. The reason is that the .NET Framework 2.0 will be supported on more platforms than BITS is (I believe BITS is only available through SP for Win2K and is native on XP and later).
If you are not familiar with BITS, it is a very cool service built into Windows that manages file downloads over the network/web. It not only stays out of the way by running as a low priority service in the background, but it also monitors your other network traffic and doesn't get in the way by hogging your bandwidth when a download is in progress. If it sees that you are frantically surfing the net looking for the last available “Tickle me Elmo” doll for your favorite niece to torture your brother/sister, or better yet playing the latest .NET Rocks! live over the net, BITS backs off and makes sure that it is not taking bandwidth that your foreground activities need. But if you are not using up your bandwidth, it will step in and use it to accomplish your downloads. If you unplug and go mobile, it will just resume the next time it sees a connection available and underutilized.
If you use Windows Update autoupdate feature, or have an MSN account and use the download manager in MSN Explorer, you are already using BITS, though you may not have realized it. Jason Clark of Wintellect had a great article in MSDN mag back in Feb on how to integrate BITS into your own apps.
So ClickOnce will be there for you in a year or so when Whidbey ships, but you are probably going to have to wait until Longhorn to see BITS supported with ClickOnce deploys.
If there is anyone from the Microsoft Windows Client team reading: Adding BITS as a configurable option to Whidbey would be the best approach if you know your target platform supports BITS!
|








| May, 2013 (1) |
| April, 2013 (2) |
| March, 2013 (2) |
| February, 2013 (2) |
| January, 2013 (2) |
| December, 2012 (3) |
| November, 2012 (1) |
| October, 2012 (1) |
| August, 2012 (2) |
| June, 2012 (2) |
| May, 2012 (3) |
| April, 2012 (1) |
| March, 2012 (2) |
| February, 2012 (2) |
| January, 2012 (1) |
| November, 2011 (4) |
| October, 2011 (1) |
| September, 2011 (2) |
| August, 2011 (1) |
| July, 2011 (1) |
| May, 2011 (5) |
| March, 2011 (4) |
| February, 2011 (2) |
| January, 2011 (3) |
| November, 2010 (4) |
| October, 2010 (1) |
| September, 2010 (5) |
| August, 2010 (5) |
| July, 2010 (6) |
| June, 2010 (8) |
| May, 2010 (2) |
| April, 2010 (2) |
| January, 2010 (1) |
| December, 2009 (3) |
| November, 2009 (2) |
| October, 2009 (3) |
| September, 2009 (3) |
| August, 2009 (2) |
| July, 2009 (3) |
| May, 2009 (3) |
| April, 2009 (2) |
| March, 2009 (1) |
| February, 2009 (2) |
| January, 2009 (2) |
| December, 2008 (1) |
| November, 2008 (2) |
| October, 2008 (5) |
| September, 2008 (4) |
| August, 2008 (2) |
| July, 2008 (1) |
| June, 2008 (2) |
| May, 2008 (2) |
| April, 2008 (3) |
| February, 2008 (6) |
| January, 2008 (3) |
| December, 2007 (1) |
| November, 2007 (1) |
| October, 2007 (5) |
| September, 2007 (1) |
| July, 2007 (3) |
| June, 2007 (8) |
| April, 2007 (2) |
| March, 2007 (4) |
| February, 2007 (1) |
| December, 2006 (2) |
| November, 2006 (9) |
| October, 2006 (5) |
| September, 2006 (3) |
| August, 2006 (2) |
| July, 2006 (4) |
| June, 2006 (5) |
| May, 2006 (10) |
| April, 2006 (4) |
| March, 2006 (2) |
| February, 2006 (12) |
| January, 2006 (7) |
| December, 2005 (2) |
| November, 2005 (15) |
| October, 2005 (6) |
| September, 2005 (7) |
| August, 2005 (3) |
| July, 2005 (10) |
| June, 2005 (11) |
| May, 2005 (7) |
| April, 2005 (8) |
| March, 2005 (6) |
| February, 2005 (2) |
| January, 2005 (6) |
| December, 2004 (3) |
| November, 2004 (5) |
| October, 2004 (2) |
| September, 2004 (5) |
| August, 2004 (13) |
| July, 2004 (6) |
| June, 2004 (14) |
| May, 2004 (17) |
| April, 2004 (12) |
| March, 2004 (8) |
| February, 2004 (10) |
| January, 2004 (14) |
| December, 2003 (9) |
| November, 2003 (13) |
| October, 2003 (3) |
Sign In
|