in

ASP.NET Weblogs

Mariano@Blog!

.NET and other interesting stuff.
  • Code Camp 2011 - Entity Framework 4.1 - Code First desde las trincheras

    Mañana voy a estar presentando la charla Entity Framework 4.1 - Code First desde las trincheras en el CodeCamp 2011 de Buenos Aires.

    A partir de el Lunes van a estar disponible en este Blog todos los recursos de la charla.

    Nos vemos allá!!!

    Update: PPT y Sources acá.

    Banner CodeCamp 300x250
  • Enamorandose de Entity Framework 4 - CodeCamp 2010

    Mañana, con mi colega Leandro Boffi, vamos a estar presentando la charla Enamorandose de Entity Framework 4 donde repasaremos los nuevos features de Entity Framework 4 en el CodeCamp 2010 de Buenos Aires.

    A partir de el Lunes va a estar disponible en este Blog todos los recursos que utilizamos para las demos.

    Los esperamos!!

    Update: Source y PPT

     

  • Me at the 'Level Extreme' .NET online magazine

    I wrote an article about Workflow Foundation Custom Activities for the .NET online magazine 'Level Extreme'.
    I hope you enjoy it!

    Thanks to MVP Martín Salías for the opportunity!

  • Send mails from .NET

    .NET offers a simple way to send mails from our applications.
    We only need to create a instance of the class MailMessage, that will represent the email, and another instance of the class Smtp that will act like a Smtp Client to send the email.
    Both of them are on the System.Net.Mail namespace.
    The source code to use is very simple:

     MailMessage mail = new MailMessage(from, to, subject, content);

     SmtpClient client = new SmtpClient();

    client.Send(mail);

    And we need to specify the configuration for the Smtp client. You can configure it to use an Exchange server.
    That can be done on the App.Config / Web.Config.

    Here is the configuration:

    <system.net>
        <mailSettings>

            <smtp deliveryMethod="Network">

                <network

                 host="mailHost"

                 port="25"

                 userName="Domain\Name"

                 password="Password"/>

            </smtp>

        </mailSettings>
    </system.net>

  • Creating a Workflow Foundation Custom Activity with Activity Derivation

    Activity derivation is one of the two methods to create Custom Activities. Unlike the composition (the another method), where with several basic activities we can create a new large and complex activity, on this method we focus on creating one single activity, defining their properties and execution model. Let's look at an example of an activity created by this method, wich will be aiming to display a message on the console.

    To do that we must create a new project of Workflow Activity Library type. We will name it “WFActivityDerivation”. and add a new class called ActivityDerivationExample.cs, which the following code:

    public class ActivityDerivationExample : Activity

    {

        string _text;

     

        public string Text

        {

            get { return _text; }

            set { _text = value; }

        }

     

        protected override ActivityExecutionStatus Execute(

        ActivityExecutionContext executionContext)

        {

            Console.WriteLine(Text);

            Console.ReadKey();

            return ActivityExecutionStatus.Closed;

        }

    }

    The class inherits from System.Workflow.ComponentModel.Activity, which is the base of all activities in WF. Our example activity exposes a property called “Text” whose value can be set from the workflow designer and which will be displayed on the console when the activity run.

    The main feature of this class is the Execute method. When we override this method we are assuming full responsability for the behavior of the activity. When the time comes to execute our custom activity, WF runtime will invoke our Execute method and then show our message on the console. After that we need to tell the WF runtime that our activity execution has ended, returning the value Closed of the ActivityExecutionStatus.

    At this point we can build our activity and create the assembly for distribution.

     

    Activity Designers:

    The Activity Designers are used to control the appearance of the activities at design time. To create a designer we need a new class that inherits from ActivityDesigner and override their virtual methods. The following example shows how to override the method OnPaint, who draws our activity in the designer's workflow:

    public class ActivityDerivationDesigner : ActivityDesigner

    {

        ActivityDerivationExample _activity;

        protected override void Initialize(Activity activity)

        {

            _activity = activity as ActivityDerivationExample;

            base.Initialize(activity);

        }

     

        protected override void OnPaint(ActivityDesignerPaintEventArgs e)

        {

            e.Graphics.FillRectangle(Brushes.Black, Location.X, Location.Y, Size.Width, Size.Height);

            Rectangle rect = new Rectangle(Location.X, Location.Y, Size.Width, 15);

            Font font = new Font("Lucida Console", 8);

            e.Graphics.DrawString(@"C:\> " + _activity.Text, font, Brushes.White, rect.X, rect.Y + 10);

     

        }

    }

    The following syntax is used to associate the designer to our activity::

    //ActivityDerivationExampe.cs

    [Designer(typeof(ActivityDerivationDesigner))]

    public class ActivityDerivationExample : Activity

    {

        //

    }

     

    With this, our activity will looks like the following picture:

    image

     

    Activity Validators:

    The Activity Validators run at design and build time, and are used to ensure that the activity has the correct settings to run. To create a validator need a new class that inherits from the class ActivityValidator and overwrite method Validate.
    For example the following validator will ensure that our activity has a valid value in the Text property:

    public class ActivityDerivationValidator : ActivityValidator

    {

        public override ValidationErrorCollection Validate(ValidationManager manager, object obj)

        {

            ValidationErrorCollection errors = base.Validate(manager, obj);

            ActivityDerivationExample activity = obj as ActivityDerivationExample;

            if (activity.Parent != null && String.IsNullOrEmpty(activity.Text))

            {

                errors.Add(ValidationError.GetNotSetValidationError("Text"));

            }

            return errors;

        }

    }

    All validation errors are added to the ValidationErrorCollection collection and returned to the caller.

    The following syntax is used to associate the validator to our activity: 

    //ActivityDerivationExampe.cs

    [ActivityValidator(typeof(ActivityDerivationValidator))]

    public class ActivityDerivationExample : Activity

    {

        //

    }

     

    Conclusion:

    The Activity Derivation allow us to create new activities that inherits from the base class Activity. You can also inherits from other classes that implement Activity, to use more features. This method gives us the highest level of control and offers us a way to extend WF code itself.

    Posted Nov 02 2007, 04:09 PM by MarianoS with 1 comment(s)
    Filed under:
  • Certificate Access Error in a IIS hosted WCF Service

    The problem appears when a WCF Service hosted in an IIS tries to load a certificate from the Windows Certificates Store with the account of the Application Pool where the service runs, and the account’s profile is not previously loaded. When a user logs on interactively, the system automatically loads the user's profile. If a service or an application impersonates a user, the system does not load the user's profile. Therefore, the service or application should load the user's profile with LoadUserProfile.

    When this happens the operation throws the following exception:

    System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

    See http://support.microsoft.com/kb/939761 Microsoft Knowledge Base Article for detailed information.

    A workaround to this problem is to load the Application Pool Identity Account´s profile before the service call is executed. Placing the code in the Application_Start() method on the Global.asax of the IIS host will solve the problem (see http://msdn2.microsoft.com/en-us/library/aa374341.aspx for detailed information).

    Here is the code:

    private ProfileManager.PROFILEINFO profile;

     

    protected void Application_Start(object sender, EventArgs e)

    {

        bool retVal = false;

        // Need to duplicate the token. LoadUserProfile needs a token with

        // TOKEN_IMPERSONATE and TOKEN_DUPLICATE.

        const int SecurityImpersonation = 2;

        dupeTokenHandle = DupeToken(WindowsIdentity.GetCurrent().Token, SecurityImpersonation);

     

        if (IntPtr.Zero == dupeTokenHandle)

        {

            throw new Exception("Unable to duplicate token.");

        }

     

        // Load the profile.

        profile = new ProfileManager.PROFILEINFO();

        profile.dwSize = 32;

        //Domain\User

        profile.lpUserName = @"MyDomain\UserName";

        retVal = ProfileManager.LoadUserProfile(dupeTokenHandle, ref profile);

     

        if (!retVal)

        {

            throw new Exception("Error loading user profile. " + Marshal.GetLastWin32Error());

        }

    }

     

    protected void Application_End(object sender, EventArgs e)

    {

        ProfileManager.UnloadUserProfile(WindowsIdentity.GetCurrent().Token, profile.hProfile);

        CloseHandle(dupeTokenHandle);

    }

     

    private IntPtr DupeToken(IntPtr token, int Level)

    {

        IntPtr dupeTokenHandle = new IntPtr(0);

        bool retVal = DuplicateToken(token, Level, ref dupeTokenHandle);

       

        if (false == retVal)

        {

            return IntPtr.Zero;

        }

     

        return dupeTokenHandle;

    }

     

    internal class ProfileManager

    {

        [DllImport("Userenv.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]

        internal static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo);

        [DllImport("Userenv.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]

        internal static extern bool UnloadUserProfile(IntPtr hToken, IntPtr hProfile);

     

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

        public struct PROFILEINFO

        {

            public int dwSize;

            public int dwFlags;

            public String lpUserName;

            public String lpProfilePath;

            public String lpDefaultPath;

            public String lpServerName;

            public String lpPolicyPath;

            public IntPtr hProfile;

        }

    }

    An alternative workaround consists in creating a Windows Service account that loads at system start-up using the Application Pool Service Identity.

    Thanks to JavierA for helping me to find the solution.

    Posted Nov 01 2007, 05:15 PM by MarianoS with no comments
    Filed under: ,
  • The beginning

    Hi, my name is Mariano, I'm from Argentina and I´m 25.
    I have programmed computers since I was 15 and I really enjoy it.
    I'm in the computer business since year 2000 and now I'm working as developer for Lagash Systems S.A. mainly with Microsoft technology.

    This is my first blog, so I hope you find it interesting!! (I will try to keep it updated!!)

More Posts