KoenV

.NET and SMTP Configuration

Sometimes I feel stupid about discovering .NET features that have been there since an old release (2.0 in this case)...

Apparently you can just use this configSecion “mailSettings” and never have to configure your SmtpClient instance in code again (no, not hard-coded):

<system.net>
    <
mailSettings
>
        <
smtp deliveryMethod="Network" from="My Display Name &lt;myname@mydomain.com&gt;"
>
            <
network host="mail.server.com"
/>
        </
smtp
>
    </
mailSettings
>
</
system.net
>

Now you can go all like:

new SmtpClient().Send(mailMessage);

…and everything is configured for you, even the from address (which you can obviously override).

Visual Studio 2010 tip: Cut empty lines

How many times you wanted to move 2 lines by cut and pasting them, but the line you cut last is actually a blank line and your actual code is removed from the clipboard? Visual Studio 2010 has an option that keeps cutting blank lines from overwriting the clipboard. Go and uncheck this one: Tools » Options » Text Editor » All Languages » General » Apply Cut or Copy commands to blank lines when there is no selection

image

Extra (related) tip

The (free) Visual Studio 2010 extension Visual Studio 2010 Pro Power Tools contains (apart from a bunch of other handy features) the commands Edit.MoveLineUp and Edit.MoveLineDown to do whatever they say they do and maps them automatically to keyboard shortcuts Alt+Up & Alt+Down.

Resharper (not-free) has similar commands for moving lines, by default mapped to Ctrl+Alt+Shift+Up/Down.

AgUnit - Silverlight unit testing with ReSharper

If you’re a ReSharper user and Silverlight 4 developer you’ll probably like this add-in that two of my co-workers created. It lets you run your Silverlight unit tests inside the Visual Studio IDE.

agunit[1]

You can get the add-in from Codeplex: http://agunit.codeplex.com/

(requires ReSharper 5 and Silverlight 4)

Generically correcting data before save with Entity Framework

Been working with Entity Framework (.NET 4.0) for a week now for a data migration job and needed some code that generically corrects string values in the database. You probably also have seen things like empty strings instead of NULL or non-trimmed texts ("United States       ") in "old" databases, and you don't want to apply a correcting function on every column you migrate.

Here's how I've done this (extending the partial class of my ObjectContext):

public partial class MyDatacontext
{
    partial void OnContextCreated()
    {
        SavingChanges += OnSavingChanges;
    }
 
    private void OnSavingChanges(object sender, EventArgs e)
    {
        foreach (var entity in GetPersistingEntities(sender))
        {
            foreach (var propertyInfo in GetStringProperties(entity))
            {
                var value = (string)propertyInfo.GetValue(entity, null);
 
                if (value == null)
                {
                    continue;
                }
 
                if (value.Trim().Length == 0 && IsNullable(propertyInfo))
                {
                    propertyInfo.SetValue(entity, null, null);
                }
                else if (value != value.Trim())
                {
                    propertyInfo.SetValue(entity, value.Trim(), null);
                }
            }
        }
    }

    private IEnumerable<object> GetPersistingEntities(object sender)
    {
        return ((ObjectContext)sender).ObjectStateManager
            .GetObjectStateEntries(EntityState.Added | EntityState.Modified)

            .Select(e => e.Entity);
    }

   
private IEnumerable<PropertyInfo> GetStringProperties(object entity)
    {
        return entity.GetType().GetProperties()
           
.Where(pi => pi.PropertyType == typeof(string));
    }

   
private bool IsNullable(PropertyInfo propertyInfo)
    {
        return ((EdmScalarPropertyAttribute)propertyInfo

            .GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false)
            .Single()).IsNullable;
    }
}

 

Obviously you can use similar code for other generic corrections.

Error pages in ASP.NET

In ASP.NET you can retrieve the last unhandled exception via:

(HttpContext.Current.)Server.GetLastError() // Server object is available as a property in Page and UserControl context

This obviously only works in the same roundtrip. If you want to retrieve this information in your error page, you got a problem because the error page is not returned in the same roundtrip. The server responds with a redirect response and a new request to the error page is automatically sent. A common workaround would be to store the exception in your Session state from the Application_Error event in Global.asax.

From ASP.NET 3.5 you can configure the redirect mode for error pages:

<customErrors mode="On" defaultRedirect="~/Error.aspx" redirectMode="ResponseRewrite" />

This way the redirect response is not sent and the error page is returned right away. That implies that the browser is not aware of a page change and cannot reflect it in the address bar, so your original URL is not replaced with the URL of the error page, which might be what you actually want…

VTM goes Surface

 My colleague Kristof wrote an article about a Surface project he did for VTM (Belgian national television) and it was used during yesterdays' election show.

Posted: Jun 08 2009, 06:15 PM by koevoeter | with 1 comment(s)
Filed under: ,
DataSource parameter for code-behind property

Here's some code for a server control "PropertyParameter" that you can use as a SelectParameter in your xyzDataSource that binds (one-way!) to a property value that is defined in code behind. This is something I need sometimes and isn't available out-of-the-box.

This method uses reflection and requires the property in code-behind to be public. There are two implementations, one for a Page and one for a UserControl. You will need to specify the Target property if you use it inside a UserControl.

This is how you use it in your markup:

<asp:ObjectDataSource ID="StatusObjectDataSource" runat="server"
    TypeName="Components.WorkflowSecurity.WorkflowComponent"
    SelectMethod="GetAvailableStatusesForEntityType">
    <SelectParameters>
        <controls:PropertyParameter Name="entityType" 
            PropertyName="EntityType" Target="Page" />
    </SelectParameters>
</asp:ObjectDataSource>

Here is the the code for the server control:

public class PropertyParameter : Parameter
{
    public enum PropertyTargetEnum
    {
        Page,
        UserControl
    }
 
    public string PropertyName { get; set; }
    public PropertyTargetEnum Target { get; set; }
 
    public PropertyParameter()
    {
        Target = PropertyTargetEnum.Page;
    }
 
    protected override object Evaluate(
        HttpContext context, Control control)
    {
        if (string.IsNullOrEmpty(PropertyName))
        {
            throw new ArgumentNullException("PropertyName");
        }
 
        Control targetControl = ResolvePropertyTarget(control);
 
        Type pageType = targetControl.GetType();
 
        PropertyInfo pi = pageType.GetProperty(PropertyName, 
            BindingFlags.Instance | 
            BindingFlags.Public | 
            BindingFlags.NonPublic);
 
        if (pi == null)
        {
            throw new InvalidOperationException(
                string.Format("Property '{0}' not found on {1}.", 
                PropertyName, Target));
        }
 
        return pi.GetValue(targetControl, null);
    }
 
    private Control ResolvePropertyTarget(Control control)
    {
        switch (Target)
        {
            case PropertyTargetEnum.Page:
                return control.Page;
 
            case PropertyTargetEnum.UserControl:
                return FindParentUserControl(control);
        }
 
        throw new ArgumentException("Invalid target type.");
    }
 
    private UserControl FindParentUserControl(Control control)
    {
        Control parent = control.Parent;
 
        while (parent != null)
        {
            if (parent is UserControl)
            {
                return (UserControl)parent;
            } 
 
            parent = parent.Parent;
        }
 
        throw new ArgumentException(string.Format(
            "'{0}' is not inside a UserControl.", 
            control.ID));
    }
}

Btw, there are two common workarounds if you don't like this implementation:

  • Store the value in a HiddenField and use a ControlParameter instead
  • Add a Parameter control; implement the OnSelecting event of the DataSource to set the value on the InputParameters collection
Warning: Generation of designer file failed: The ... tag has already been registered.

Weird problem in ASP.NET again... With a weird solution:

In my apps I always have a folder UserControls where I put UserControls (not custom or server controls) that I use throughout the site. Examples are a date textbox with validation, formatted labels, upload fields, toggled image buttons, error message labels, etc. I register all these controls globally in the web.config pages section, like this:

<pages>

    <controls>

        <add tagPrefix="myapp" tagName="WebUserControl1"

             src="~/UserControls/WebUserControl1.ascx"/>

        <add tagPrefix="myapp" tagName="WebUserControl2"

             src="~/UserControls/WebUserControl2.ascx"/>

    </controls>

</pages>

The problem is that some user controls also use another user control from that same folder, which leads to the following ASP.NET parser error:

Parser Error Message: The page '/UserControls/WebUserControl1.ascx' cannot use the user control '/UserControls/WebUserControl2.ascx', because it is registered in web.config and lives in the same directory as the page.

The solution for that is to add a @Register directive to WebUserControl1.ascx like this:

<%@ Register TagPrefix="myapp" TagName="WebUserControl2" Src="~/UserControls/WebUserControl2.ascx" %>

But now I get the error from the blog post title, so if I add new controls to the user control, the designer file is not updated and I cannot access these in code behind (unless I update the designer file manually - NOT).

The key to resolve is to either pick a different TagPrefix or TagName in the @Register directive and use it like that, e.g.:

<%@ Register TagPrefix="myappLocal" TagName="WebUserControl2" Src="~/UserControls/WebUserControl2.ascx" %>

<myappLocal:WebUserControl2 runat="server" />

or

<%@ Register TagPrefix="myapp" TagName="WebUserControl2Local" Src="~/UserControls/WebUserControl2.ascx" %>

<myapp:WebUserControl2Local runat="server" />

Now the designer file keeps updating...

Exceptional exception handling

My (much more productive) colleague Davy beat me to post this problem we had today at work, so I'm gonna be lazy and link to him (and steal his title).

Btw yesterday we applied this "solution" to one of our biggest projects and -hooray- it worked...

LINQPad

Joseph Albahari created this great tool to execute LINQ (but also SQL) queries and review the results. In case of LINQ you also get to see the corresponding compiler translation and SQL query.

Some pro's:

  • Great for testing LINQ without having to build and debug your entire application in Visual Studio...
  • No installation (just exe)
  • Self updating
  • You can choose between C# and VB
  • Includes query organizer
  • ...

 LINQPad

Get it here: www.linqpad.net

PS: Also take the LINQ quiz here: www.albahari.com/nutshell/linqquiz.html

Posted: Mar 17 2008, 01:32 PM by koevoeter
Filed under: ,
More Posts Next page »