April 2006 - Posts
I discovered how great the new System.Net.Mail namespace is this weekend.
The now obsoleted System.Web.Mail was just a wrapper around CDONTS. It worked pretty well. It would churn out messages into the C:\InetPub\MailRoot\Pickup folder. So in a web farm we would configure the smtp service to route mail to a "smarthost". In our case we configured the smart host to route the mail through our exchange server. You could write your own code to set the relay server most likely reading the setting from your web.config’s appSettings.
After upgrading a web project to ASP.NET 2.0 I noticed several warnings about System.Web.Mail being obsolete and I should use System.Net.Mail. Well, this turned out to be a brain dead simple thing to convert and in the end it works even better. Here is the old way:
MailMessage message = new MailMessage();
message.To = "to@foo.com";
message.From = "from@bar.com";
message.Subject = "Hello subject";
message.Body = "Hello body";
// you can set the relay server in code like this:
// SmtpMail.SmtpServer = ConfigurationSettings.AppSettings["SmtpServer"];
SmtpMail.Send(message);
All you have to do to convert is change your using statement from System.Web.Mail to System.Net.Mail and use and instance of SmtpClient class rather than the static SmtpMail class:
MailMessage message = new MailMessage();
message.To = "to@foo.com";
message.From = "from@bar.com";
message.Subject = "Hello subject";
message.Body = "Hello body";
SmtpClient smtp = new SmtpClient();
smtp.Send(message);
Not a lot of difference there. But here’s the cool thing. You can control how it sends the email with the web/app.config like this:
<system.net>
<mailSettings>
<smtp deliveryMethod="Network">
<network host="mail.mydomain.com" port="25" />
</smtp>
<!-- Use this setting for development
<smtp deliveryMethod="SpecifiedPickupDirectory">
<specifiedPickupDirectory pickupDirectoryLocation="C:\Temp" />
</smtp>
-->
</mailSettings>
</system.net>
Now I can have it drop the messages in a temp folder when I’m developing and have the production web.config relay the email through the main email server.
It’s also worth noting that the old System.Web.Mail.SmtpMail was single threaded. If you needed to do a lot of email processing it would totally suck. Take a look at what the send on the old one did:
public static void Send(MailMessage message)
{
lock (SmtpMail._lockObject)
{
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
throw new PlatformNotSupportedException(SR.GetString("RequiresNT"));
}
if (Environment.OSVersion.Version.Major <= 4)
{
SmtpMail.CdoNtsHelper.Send(message);
}
else
{
SmtpMail.CdoSysHelper.Send(message);
}
}
}
Yuck! This was a nice bottleneck. As apposed to:
public class SmtpClient
{
// Events
public event SendCompletedEventHandler SendCompleted;
// Methods
public void Send(MailMessage message);
public void Send(string from, string recipients, string subject, string body);
public void SendAsync(MailMessage message, object userToken);
public void SendAsync(string from, string recipients, string subject, string body, object userToken);
public void SendAsyncCancel();
}
SmtpClient is not a static class like SmtpMail was. So you can have many email sends going at the same time. Plus notice the Async versions of the Send method. This is much more conducive to NT services or Windows Forms applications that need to send emails.
This is really frustrating. I used to ba able to script stored procs from the server explorer into a data project. It would create a single file for each proc and would look something like this:
IF EXISTS
(SELECT * FROM sysobjects WHERE type = 'P' AND name = 'Stored_Procedure_Name')
BEGIN
DROP Procedure Stored_Procedure_Name
END
GO CREATE Procedure
Stored_Procedure_Name
AS
... GO
This was great. I could check the scripts into source control. I could use VS.NET to maintain the procs and just right click and select "run on" to deploy it to the sql instance. This seems to have taken a turn for the worse in 2005. All I can get it to create now is this:
/****** Object:
StoredProcedure [dbo].[Stored_Procedure_Name] Script Date: 04/23/2006 10:55:50 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Stored_Procedure_Name]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[Stored_Procedure_Name]
GO
/****** Object: StoredProcedure [dbo].[Stored_Procedure_Name] Script Date: 04/23/2006 10:55:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Stored_Procedure_Name]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
CREATE Procedure dbo.Stored_Procedure_Name
AS
/*
Code goes here
*/
'
END
GO Wow. this is totally useless for my purposes. Wy does it generate a dynamic sql with an exec? What the heck? I guess your supposed to code all your procs on the db server and then go back at some point and rescript them out and put them into source control. Hopefully there is some way to customize the script template that its using.
I know this isnt a problem if you create a data project from the beginning and just add strored procedure scripts as you go. What about those people that already have a mass of procs in their db server that they want to migrate to a dataproject for source control purposes?
I know I'm just missing something obvious. I can't wait until I can just slap my forhead and move on.
Well, I traded in the corporate uniform for a jeans and t-shirt startup. As of today I am officially working for learnvisualstudio.net. This change has been a long time coming and I'm sure Bob is glad the waiting is over. While I will certainly miss all the great people at my previous job (Mary Kay), this is a great opportunity for me. I look forward to having the time and responsibility to be more involved with the .NET community.
My role at LVS is to support the member forums, engage the .NET community and research and develop supporiting materials for LVS content. Bob will still be producing the video content. I will simply do the research for the content so he can concentrate on running the biz and producing videos.
I just took the MacBook Pro plunge. I must say it was very sureal to go through the XP install on Apple hardware. I got all my VPCs running under XP and VS.NET 2005. Looks like it will make a pretty sweet development machine. Since I love to play with technology, I'm looking forward to having access to both OS X and Windows. Now I can do my Ruby on Rails experiments properly. :)
I had similar troubles when intalling XP as Jeff did. Doing a repair on XP and re-installing the drivers seems to have cured all.
The text/xml-script declarative model is great. I'd just like to see it declared outside of the .aspx file. Semething like an "ajax" behind file.
Imagine:
Default.aspx
Default.aspx.cs
Default.aspx.ajax <-- declarative text/xml-script
Most of the Atlas markup I've seen in demo apps is just control bindings and web service proxy declarations. The contents of the tex/xml-script blocks seem to more resemble a mapping file than ui component instantiation.
This should be possible to do by just setting src attribute on the <SCRIPT> element. e.g.:
<script type="text/xml-script" src="Default.aspx.ajax"></script>
This currently doesnt seem to work. I'm sure its because the content type is mixed up. I know this is nit picky but having the atlas declarative block in the HTML markup feels like putting css or script inline.
This also leads to the possiblity of using a "js" behind where you can do all of your client side declarations with simple javascript calls to the atlas script library. This seems on par with everything else coming out of Microsft. If you like to just write code you can do that. If you like to "declare" things with angle brackets your good to go there as well.
For now its back to experimenting...
P.S. The documentation for the March CTP is soooooo much better.
I was just reading through this post: http://weblogs.asp.net/mschwarz/archive/2006/04/03/441767.aspx and it reminded me of some of the worries that I have about the various AJAX libraries.
We have some devs here that are prototyping some AJAX features. They are mainly using the controls from Component Art (which are great btw). The Component Art controls have alot in common with the things that ATLAS is doing. The idea here is to enable "ASP.NET" developers to come in and AJAXify their web apps. The thing is they end up getting completely thrown for a loop when the ASP.NET postback model starts getting in their way (viewstate issues etc.). For simple little autocomplete boxes and such this is no problem. But once you go off and try to do anything complex it just confuses the developers. The notion that you can remain AJAX ignorant and just sling controls is seeming farther and farther away from reality each day. Maybe theres an 80/20 rule here but so far it sure seems to be more like 20/80.
This also smacks of the orginal goals of the Web Forms design time: let the VB windows programmers come on over and play in the web sandbox. While this sounds great on paper and works for demos and one off sites, it leads to piles of spaghetti code for large web sites.
If your serious about doing AJAX then make sure you understand JavaScript. It will be the most important thing you learn when you go to code and debug an AJAX app.
I've been looking forward to ATLAS so I havnt really looked at AJAX.Net that closely. I know more about it through the posts here on weblogs than I do from actually diving into it. Looks like I will be correcting that very soon now. :)
I've been looking at Ruby on Rails recently to see what all the noise has been about. I have to say I'm pretty impressed. The front controller design has enabled them to graft on AJAX features pretty cleanly. The prototype javascript library has the same feel as ruby does which is great for keeping the programming model as consistant as possible.
ATLAS is trying to do the same thing for ASP.NET but fitting it into the page controller model may be a bit more challenging.
More Posts