Tuesday, 30 December 2008

JS error "Sys is not defined" caused by HttpModule

I have an ASP.NET application that makes use of Ajax Control Toolkit. Everything was working fine until I decided to implement authentication on application level using HttpModules. It's basically about authenticating each request to your application with one piece of code - before each request is processed the code defined in appropriate HttpModule is executed. You can read more on that here or here.

After I've configured my application to use the custom authentication HttpModule all controls from Ajax Control Toolkit (ACT) stopped working. Instead, I was getting JavaScript error "Sys is not defined". The cause of that was the authentication module, which was checking URL parameters to grant access to requested resources.

I've discovered that ACT was dynamically loading additional .resx files from the server. The dynamic requests (sort of Ajax calls) didn't contain appropriate parameters so they were rejected.

Solution:

I've added additional if clause to my authentication code that was allowing all requests to .axd files to pass, regardless parameters. I could do that since none of the files created by me was in that format and I didn't have to care about authentication when such files are requested. Of course, I'm open for suggestions how to resolve this in cleaner way.

Friday, 5 December 2008

How to get assembly file from GAC?

The .Net application I'm currently working on uses libraries from Global Assembly Cache (GAC). To see the libraries available in GAC just navigate to C:\windows\assembly with regular windows file explorer. The explorer will display the GAC content in a different way than regular files. You'll only see the list of available libraries. You can add assemblies to GAC by drag'n'drop:

Global Assembly CacheHowever, this view will only allow you to see the current GAC content and add/update libraries. This has some limitations e.g.:
  • It won't let you get the actual library file. Sometimes you may need to do that e.g. to backup file from GAC before you replace it.

  • You can't add files of different types e.g. PDB files. This could be useful if you'd like to see the line numbers in stack trace.

  • ...

You can bypass all those limitations by using different tool to access the folder content e.g. console or Total Commander. Note that the libraries placed in GAC are not saved directly in c:\windows\assembly folder. The dll-s you're looking for should be available at following path:
C:\windows\assembly\GAC_MSIL\Namespace.Project\
<assembly_version_number>__<assembly_public_token_key>\Namespace.Project.dll

Example
We're looking for library with name = Kainos.Framework.Web, version = 1.0.0.0 and PublicTokenKey = 1111aaaa1111aaaa. You can find it at:
C:\windows\assembly\GAC_MSIL\Kainos.Framework.Core\
1.0.0.0__1111aaaa1111aaaa\Kainos.Framework.Core.dll
Once you access the folder you can copy the assembly files, add pdb files, etc.

Thursday, 20 November 2008

IIS Error: "Unexpected Error 0x8ffe2740 Occurred"

When I try to start IIS the following error message is displayed:
"Unexpected Error 0x8ffe2740 Occurred"

Solution:
This happens because some required ports are not available. The most common application using required ports is Skype. You can conigure Skype to not use these ports:

  1. Open Skype

  2. Choose Tools > Options > Advanced > Connections

  3. Uncheck Use Port 80 and 443 as alternatives for incoming connections.

  4. Restart Skype

  5. Start IIS

Saturday, 1 November 2008

Error while exporting pages from SharePoint using SP Designer

While opening Sharepoint pages containing webparts using SP Designer I was getting the following error message:
"This page cannot be edited in Sharepoint Designer. You can edit the content in the browser, or edit the corresponding page layout in Sharepoint designer."



Solution:

  1. Open you Site Structure in SharePoint Designer

  2. Right click on your page and select “Detach from page layout”

  3. This will check the file out and right click again and select open > open with notepad

  4. This will display the content you need to export. You can save it to chosen location

Friday, 26 September 2008

Custom validaton in CSLA.NET

Recently I was assigned to a new project which bases on CSLA.NET framework. One of my first tasks was to extend the validation of some business objects. Unfortunetly the Csla.Validation.CommonRules were not enough in my case since I needed to validate the value of one business object property against the value of another one. Here is sample code that checks whether Range.MaxValue is greater than Range.MinValue:
public class Range : Csla.BusinessBase<Range>
{
//members and properties declaration
private int _minValue = 0;
private int _maxValue = 0;

public int MaxValue { get { (...) } set { (...) } }
public int MinValue { get { (...) } set { (...) } }

(...)

protected override void AddBusinessRules()
{
//Change of MaxValue will cause validation of MinValue as well
ValidationRules.AddDependantProperty("MaxValue", "MinValue");

//prepare parameters for valdiation method
Dictionary<string, object> parameters =
new Dictionary<string, object>(1);
parameters.Add(CustomRules.DATE_TO_COMPARE, "MinRange");
DecoratedRuleArgs args =
new DecoratedRuleArgs("MaxRange", parameters);

//add custom validation rule
ValidationRules.AddRuleRule<Rule>(
CustomRules.DateGreaterThan, args);
}
}

public class CustomRules
{
///
/// Checks whether the property value is DateTime and is greater than
/// value specified in field whose name is passed as the argument
/// called as defined in DATE_TO_COMPARE const.
///

///
/// True if date is greater than the date to compare against.
///

///
/// Thrown when impossible to convert any of both dates to DateTime.
///

public static bool DateGreaterThan<T>(T target, RuleArgs e)
{
DecoratedRuleArgs args = (DecoratedRuleArgs)e;

DateTime lesserDate =
(DateTime)Csla.Utilities.CallByName(target,
(string)args[DATE_TO_COMPARE], CallType.Get);
DateTime greaterDate =
(DateTime)Csla.Utilities.CallByName(target,
e.PropertyName, CallType.Get);

if (lesserDate < greaterDate)
{
// date is valid
return true;
}
else
{
// date is invalid - prepare error message
e.Description = e.PropertyFriendlyName +
" has to be greater than " +
(string)args[DATE_TO_COMPARE];
return false;
}
}

}

Tuesday, 1 July 2008

Accessing static properties using C# reflections

Using C# reflections is quite easy. I found some good examples here. However, most of the examples available on the Web do not cover static class members. In order to access a static class member you don't need to use Activator since you don't need the class instance. Here is a simple example for accessing static property:
//Get type of MyClass
Type myType = Type.GetType("MyNamespace.MyClass");

//Get PropertyInfo for property SomeProperty
PropertyInfo pi = myType.GetProperty("SomeProperty");

//Display property value on console.
//Because it's static you can pass nulls for both object and index
Console.WriteLine("Value of my property is: " +
pi.GetValue(null, null));

Monday, 9 June 2008

MonoRail & ActiveRecord localized validation messages

I'm currently developing .NET web application using MonoRail framework and ActiveRecord design pattern. One of the requirements for the project is easy localisation. In general it's pretty straightforward but I had some troubles figuring out how to localize the validation messages coming from ActiveRecord Business Objects.

Here's my solution for that:

  1. Create validation messages in resource file
    In your resource file (e.g Validation.resx) add entries for validation messages, e.g.


    Of course, you'll need to define those entries in resource files for all languages your application should support (e.g. in Validation.de.resx for German, Validation.es.resx for Spanish, etc.).

  2. Add business objects validation attributes
    Let's use a sample business object representing User, which only includes name property. We have to add ActiveRecord attributes for validation e.g. ValidateNonEmpty and ValidateLength using appropriate parameters. These both attributes take the validation message as one of the arguments. Instead of giving here the actual message we can use its ID (name) from the resource file e.g. "vldNameRequired". Here is sample code of such Business Object:
    [ActiveRecord("User")]
    public class User : ActiveRecord
    {
    [Property(NotNull = true, Length = 50)]
    [ValidateNonEmpty("vldNameRequired")]
    [ValidateLength(1, 50, "vldNameLength")]
    public string Name { get; set; }
    }
    For more validation attributes please refer to ActiveRecord documentation.

  3. Catch validation errors
    Now, we have to enable validation for appropriate action. Let's say we want to validate data provided by the user while creating new account. For registering new user I've created the Register method together with appropriate data binds. Firstly we need to allow validation for that action (Validate = true).
    Catching validation errors is described in comments in code below:
    (...)
    using System.Resources;

    public class UserController : SmartDispatcherController
    {
    (...)
    public void Register([DataBind("User", Validate=true)]User user)
    {
    // Check whether the binded object is valid by calling the
    // HasValidationError inherited from SmartDispatcherController
    if (HasValidationError(user))
    {
    // If there are validation errors we can access the error
    // summary using GetErrorSummary method
    ErrorSummary summary = GetErrorSummary(user);

    // Now we have to populate Flash item with localized
    // validation messages by calling local private
    // method GetLocalizedMessages
    Flash["validationErrors"] = GetLocalizedMessages(summary);
    PropertyBag["user"] = user;
    }
    else
    {
    //If there are no errors save the new user and redirect
    //to other action
    User.Save(user);
    RedirectToAction('DoSomethingElse');
    }
    }

    /// <summary>
    /// Translates the message IDs to actual messages
    /// </summary>
    /// <param name="messageIDs">Message IDs to translate</param>
    /// <returns>Array of translated messages</returns>
    private string[] GetLocalizedMessages(string[] messageIDs)
    {
    string[] messages = new string[messageIDs.Length];
    for (int i=0;i<messageIDs.Length;i++)
    {
    // YourNamespace.Validation is the full name of your
    // resource file with validation messages
    messages[i] = YourNamespace.Validation.
    ResourceManager.GetString(messageIDs[i]);
    if (messages[i] == null)
    {
    // ERR_NO_RESOURCE is constant storing ID of default
    // error msg
    messages[i] = Validation.ResourceManager.
    GetString(ERR_NO_RESOURCE);
    }
    }
    return messages;
    }
    }
  4. Display localized validation messages
    Now you have to display validation error messages on the page. This is the sample code that displays all validation errors coming from ActiveRecord validation (I'm using NVelocity as my view engine):

    #if($validationErrors != null && $validationErrors.Length > 0)
    <ul class="validationErrors">
    #foreach($ve in $validationErrors)
    <li>$ve</li>
    #end
    </ul>
    #end
That's it. There are of course many possibilities for implementing that functionality. One of the enhancements could translate the ErrorSummary to the Dictionary<PropertyName, ValidationErrorMsg> so you can display error messages next to appropriate controls.

Wednesday, 7 May 2008

Generating C# Web Service Skeleton from wsdl

I need to create a C#.NET web service which adheres to a specific wsdl provided by a third party. Instead of browsing the wsdl content and creating the service manually I decided to look for a tool that provides a similar functionality to wsdl2java tool. What I found is wsdl.exe.

In order to generate a C# Interface for my web service I run this tool with options:
wsdl /language:CS /serverInterface wsdl_location
The command above generates the file "<wsdl _file_name>Interfaces.cs" in default location. Copy generated file to your web service project and create a new class implementing interface from generated file.

Example:
Let's assume we used the wsdl tool and have the generated interface for our service. The interface name is IMyServiceHttpBinding and contains the signatures of 2 methods: void foo(string text) and string goo(). Sample implementation may look as follows:

[WebService(Namespace = "http://somenamespace.com")]
public class MyService : IMyServiceHttpBinding
{
public void foo(string someText) {(...)}

public string goo() {(...)}
}

Enabling SSL in IIS 5

Currently I'm using Windows XP Pro and have IIS 5.1 installed. I tried to enable SSL for my IIS. Most of the instructions were quite complex, describing the manual generation and signing of certificates. However, I found much simpler solution which allows to enable SSL in few simple steps.

Basically, all you need to do is install IIS 6.0 Resource Kit and run the SelfSSL tool. That's it! The generated certificate is 'self-signed' so it may be suggested as untrusted by client's browser but it's completely enough for developers who need to test connections to their IIS using SSL.

I found this solution here.