ASPHostDirectory.COM Cheap ASP.NET MVC Hosting

Blog about ASP.NET MVC Hosting and its Technology

ASPHostDirectory ASP.NET MVC Hosting :: Create ASP.NET MVC Localization with Language Detection

clock October 22, 2010 06:06 by author Darwin

Introduction

In this tutorial we will show a simple way to create localization (globalization) for web application using APS.NET MVC framework. It should work fine with MVC 1 and 2 and were currently using .NET 3.5 SP1, but .NET 4.0 will work as well. All code is in C# and for language translations we use XML files.

Language files with XML

For translations of different languages we use simple xml files. We store them in App_Data/messages/<locale>.xml, for example en-US.xml or de-DE.xml. Here is the xml structure:

<items>
  <item key="home">Home</item>
  <item key="products">Products</item>
  <item key="services">Services</item>
</items>

You should have identical language files for all desired languages. All translation items should be the same (with equal “key” attributes).

Create Translator class

Main translation work will be done by Translator singleton class. Create “Infrastructure” folder in your MVC project and put class Translator there.
First, let’s make class singleton:

private static Translator instance = null;
public static Translator Instance
{
    get
    {
        if (instance == null)
        {
            instance = new Translator();
        }
        return instance;
    }
}
private Translator() { }

Add the following fields and properties to the class:

private static string[] cultures = { "en-US", "bg-BG" };
private string locale = string.Empty;

public string Locale
{
    get
    {
        if (string.IsNullOrEmpty(locale))
        {
            throw new Exception("Locale not set");
        }
        else
        {
            return locale;
        }
    }
    set
    {
        if (Cultures.Contains(value))
        {
            locale = value;
            load();
        }
        else
        {
            throw new Exception("Invalid locale");
        }
    }
}

public static string[] Cultures
{
    get
    {
        return cultures;
    }
}

Field "cultures" lists available cultures. "Locale" keeps current culture. And in "set" part of Locale property you can see invocation of load() method. We will talk about it later.
To keep localization data I will create simple dictionary and then use keys from XML for dictionary keys and XML item values as dictionary values. Simple Translate method will do translation job. We have indexer method for easy access.

private Dictionary data = null;

public string Translate(string key)
{
    if (data != null && data.ContainsKey(key))
    {
        return data[key];
    }
    else
    {
        return ":" + key + ":";
    }
}

public string this[string key]
{
    get
    {
        return Translate(key);
    }
}

If some key cannot be found and translated, we return the key with ":" around it, so you can easy find untranslated items.
Finally, for loading XML we use LINQ to XML. we have static caching dictionary, so I don't need reading XML on every request.

private static Dictionary<string, Dictionary<string, string>> cache =
  new Dictionary<string, Dictionary<string, string>>();

private void load()
{
    if (cache.ContainsKey(locale) == false) // CACHE MISS !
    {
        var doc = XDocument.Load(
            HttpContext.Current.Server.MapPath(
               "~/App_Data/messages/" + locale + ".xml"));

        cache[locale] = (from item in doc.Descendants("item")
                         where item.Attribute("key") != null
                         select new
                         {
                             Key = item.Attribute("key").Value,
                             Data = item.Value,
                         }).ToDictionary(i => i.Key, i => i.Data);
    }

    data = cache[locale];
}

public static void ClearCache()
{
    cache = new Dictionary<string, Dictionary<string, string>>();
}

You can use translator in your controller like this:
Translator.Instance[key];
After load() methid we have ClearCache method for easy developing (you know, once read, data is cached and you have to restart IIS Application Pool to refresh localization data).
Translator class is ready, we will show you how to use it later.

Create localization helpers

Create static class LocalizationHelpers and put it in "Helpers" folder in your project.

public static string CurrentCulture(this HtmlHelper html)
{
    return Translator.Instance.Locale;
}

public static string T(this HtmlHelper html, string key)
{
    return html.Encode(Translator.Instance[key]);
}

public static string T(this HtmlHelper html, string key,
    params object[] args)
{
    return html.Encode(string.Format(
        Translator.Instance[key], args));
}

We will use this in html views for translation like this

<%= Html.T("products") %>

If you want params in translated values you can use second T implementation like string.Format. First helper CurrentCulture is used in language select user control to determine current culture.

Create BaseController class

Create BaseController class that extends Controller and put it in "Infrastructure" folder of your MVC project. You should extend all your controller classes from this class. Create simple property for current selected culture (locale)

public string CurrentCulture
{
    get
    {
        return Translator.Instance.Locale;
    }
}

You will use this in your controller when you initialize your model, for example.
In the following code I will explain language detection and saving with cookie.

private void initCulture(RequestContext requestContext)
{
    string cultureCode = getCulture(requestContext.HttpContext);

    requestContext.HttpContext.Response.Cookies.Add(
        new HttpCookie("Culture", cultureCode)
        {
            Expires = DateTime.Now.AddYears(1),
            HttpOnly = true,
        }
    );

    Translator.Instance.Locale = cultureCode;

    CultureInfo culture = new CultureInfo(cultureCode);
    System.Threading.Thread.CurrentThread.CurrentCulture = culture;
    System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
}

private string getCulture(HttpContextBase context)
{
    string code = getCookieCulture(context);

    if (string.IsNullOrEmpty(code))
    {
        code = getCountryCulture(context);
    }

    return code;
}

private string getCookieCulture(HttpContextBase context)
{
    HttpCookie cookie = context.Request.Cookies["Culture"];

    if (cookie == null || string.IsNullOrEmpty(cookie.Value) ||
         !Translator.Cultures.Contains(cookie.Value))
    {
        return string.Empty;
    }

    return cookie.Value;
}

private string getCountryCulture(HttpContextBase context)
{
    // some GeoIp magic here
    return "en-US";
}

First we try to get language cookie if there is any (if this is not first time visit). If there is no cookie you can detect browser language, make GeoIP IP address lookup and so on. After finding some valid locale/culture we set response cookie for next page visits. After this we change current thread culture. This is useful if you want to format some date or currency values.
You should call initCulture in overridden Initialize method.

Changes in HomeController

Don't forget to change parent class of all your controller to BaseController. Add following code to your HomeController, so you can change current culture. When you open specified URL, a cookie is set and user is redirected to index page. This URL is like example.com/home/culture/en-US. Clear cache method is for deleting current cache without restarting application pool. Access it with example.com/home/ClearLanguageCache

public ActionResult Culture(string id)
{
    HttpCookie cookie = Request.Cookies["Culture"];
    cookie.Value = id;
    cookie.Expires = DateTime.Now.AddYears(1);
    Response.SetCookie(cookie);

    return Redirect("/");
}

public ActionResult ClearLanguageCache(string id)
{
    Translator.ClearCache();

    return Redirect("/");
}

To change current language we will create special user control which will be included in may Master.Site layout. Create CultureUserControl.ascx and put it in Views/Shared/ folder of your MVC project. Here is the code:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<% if (Html.CurrentCulture() == "bg-BG") { %>
    <a id="lang" href="/home/culture/en-US">en</a>
<% } else { %>
    <a id="lang" href="/home/culture/bg-BG">bg</a>
<% } %>

In our layout we use <% Html.RenderPartial("CultureUserControl"); %> to include it.

Conclusion

In this simple tutorial we've created localization infrastructure for ASP.NET MVC web application. Translations of different languages are stored in XML files. Then we use Translator class to load them. Current user culture is kept in cookie. You can access Translator class in html views using some helpers. Also all the translation data we cached so it will not be loaded form XML every request.
Hope this tutorial helps.

What is so SPECIAL on ASPHostDirectory.com ASP.NET MVC Hosting?

We know that finding a cheap, reliable web host is not a simple task so we’ve put all the information you need in one place to help you make your decision. At ASPHostDirectory, we pride ourselves in our commitment to our customers and want to make sure they have all the details they need before making that big decision.

We will work tirelessly to provide a refreshing and friendly level of customer service. We believe in creativity, innovation, and a competitive spirit in all that we do. We are sound, honest company who feels that business is more than just the bottom line. We consider every business opportunity a chance to engage and interact with our customers and our community. Neither our clients nor our employees are a commodity. They are part of our family.

The followings are the top 10 reasons you should trust your online business and hosting needs to us

- FREE domain for Life - ASPHostDirectory gives you your own free domain name for life with our Professional Hosting Plan and 3 free domains with any of Reseller Hosting Plan! There’s no need to panic about renewing your domain as ASPHostDirectory will automatically do this for you to ensure you never lose the all important identity of your site
- 99,9% Uptime Guarantee - ASPHostDirectory promises it’s customers 99.9% network uptime! We are so concerned about uptime that we set up our own company to monitor people’s uptime for them called ASPHostDirectory Uptime
- 24/7-based Support - We never fall asleep and we run a service that is opening 24/7 a year. Even everyone is on holiday during Easter or Christmast/New Year, we are always behind our desk serving our customers
- Customer Tailored Support - if you compare our hosting plans to others you will see that we are offering a much better deal in every aspect; performance, disk quotas, bandwidth allocation, databases, security, control panel features, e-mail services, real-time stats, and service
- Money Back Guarantee - ASPHostDirectory offers a ‘no questions asked’ money back guarantee with all our plans for any cancellations made within the first 30 days of ordering. Our cancellation policy is very simple - if you cancel your account within 30 days of first signing up we will provide you with a full refund
- Experts in ASP.NET MVC Hosting - Given the scale of our environment, we have recruited and developed some of the best talent in the hosting technology that you are using. Our team is strong because of the experience and talents of the individuals who make up ASPHostDirectory
- Daily Backup Service - We realise that your website is very important to your business and hence, we never ever forget to create a daily backup. Your database and website are backup every night into a permanent remote tape drive to ensure that they are always safe and secure. The backup is always ready and available anytime you need it
- Easy Site Administration - With our powerful control panel, you can always administer most of your site features easily without even needing to contact for our Support Team. Additionally, you can also install more than 100 FREE applications directly via our Control  Panel in 1 minute!

Happy Hosting



ASPHostDirectory ASP.NET MVC 2.0 Hosting :: Remote Validation with ASP.NET MVC 2

clock October 11, 2010 10:32 by author Darwin

One validation feature that we didn’t quite have time for in MVC 2’s new client-side validation support is called “remote validation”.

Remote validation means we make a call back to our web site to ensure that a given value is valid. You might want this in cases where it’s not easy (or possible) to determine whether the value is valid on the client side, but you’d still like to give the user client-side feedback about the validity of the item. The canonical example is checking to see if a desired username is taken during your site registration process.

This is an example remote validator that I modified from an example by Levi Broderick (who did the bulk of the JavaScript work for client-side validation). This example was tested on MVC 2 RC, and assumes that you’re using the DataAnnotations validation system (the default).

In order to make this work, we will need to perform a couple of one-time steps:

1. Include a JavaScript file that enables remote validation.
2.
Register a server-side adapter for remote validation.

We’ll also need to perform a couple of steps for each remote validation we want to perform:

1.
Write an action which accepts the value to be tested and returns a string, either “true” (the model is valid), “false” (the model is invalid and you want to use the default message), or any other string (the model is invalid, and the string that we return should be the error message).

2.
Put the [Remote] attribute to the model property that you want remotely validated, pointing to the action you just wrote.

The Client-Side Bits

When you want to write a client-side validator for MVC 2, you will write a function (in JavaScript) that registers the validator and performs the validation when prompted to. For remote validation, this is our example JavaScript:

Sys.Mvc.ValidatorRegistry.validators.remote = function(rule) {
    var url = rule.ValidationParameters.url;
    var parameterName = rule.ValidationParameters.parameterName;
    var message = rule.ErrorMessage;

    return function(value, context) {
        if (!value || !value.length) {
           return true;
        }

        if (context.eventName != 'blur') {
           return true;
        }

        var newUrl = ((url.indexOf('?') < 0) ? (url + '?') : (url + '&'))
                    + encodeURIComponent(parameterName) + '=' + encodeURIComponent(value);

        var completedCallback = function(executor) {
           if (executor.get_statusCode() != 200) {
              return;
           }
 
           var responseData = executor.get_responseData();
           if (responseData != 'true') {
              var newMessage = (responseData == 'false' ? message : responseData);
              context.fieldContext.addError(newMessage);
           }
        }

        var r = new Sys.Net.WebRequest();
        r.set_url(newUrl);
        r.set_httpVerb('GET');
        r.add_completed(completedCallback);
        r.invoke();
        return true;
    };
};

Put this in a .js file, and reference it in the same place where you’re already referencing MicrosoftAjax.js and MicrosoftMvcValidation.js (usually in your Site.Master file or some equivalent).

The first line sets up a new client-side validation rule named “remote”. The anonymous function sets up the rule, and returns a function which performs the validation. The function accepts the value and a context object we create for you which contains information about the actual validation you’re doing.

The first if block stops us from doing anything is there’s no value. Validators should always return success (true) when given an empty value, because it’s the “required” validator that’s responsible for denying empty values.

The second if block only runs our validation during the “blur” event (i.e., when the user tabs out of the field). The other two events are “input” (fired as the user types) and “submit” (fired when the user wants to submit the form). Neither of these are appropriate because “input” would happen too much, and “submit” is too late for a remote validation. One consequence of this is that, with this implementation, users will be allowed to submit values to the server where the remote validation might’ve failed. You could change this JS file to prevent that (stash the previous result from your “blur” event and return that during the “submit” event), but I’ll leave that as an exercise for the reader.

We append the value to the URL and submit a new GET request to the URL, and then hook the response to read the result, setting a validation error message if the response was anything other than “true”.

The Server-Side Bits

We’ll start with the RemoteAttribute class:

using System;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using System.Web.Routing;

[AttributeUsage(AttributeTargets.Property)]
public class RemoteAttribute : ValidationAttribute
{

    protected RemoteAttribute(string parameterName
    {
                   ParameterName = parameterName;
        RouteData = new RouteValueDictionary();
    }

    public RemoteAttribute(string action, string controller, string parameterName)
        : this(parameterName)
    {
        RouteData["controller"] = controller;
        RouteData["action"] = action;
    }

    public RemoteAttribute(string routeName, string parameterName)
        : this(parameterName)
    {
        RouteName = routeName;
    }

    public string ParameterName { get; protected set; }

    protected RouteValueDictionary RouteData { get; set; }

    protected string RouteName { get; set; }

    public virtual string GetUrl(ControllerContext controllerContext)
    {
        var pathData = RouteTable.Routes.GetVirtualPath(controllerContext.RequestContext,
                                 RouteName,
                                 RouteData);

        if (pathData == null)
           throw new InvalidOperationException("No route matched!");
        return pathData.VirtualPath;
    }

    public override bool IsValid(object value)
    {
        return true;
    }
}

This attribute derives from the DataAnnotations ValidationAttribute base class. There’s no server-side validation by default (the “return true” line in IsValid), though you could derive from this attribute to provide both server- and client-side validation. We’ll talk about this more in a bit.

There are two constructors: one where you provide action + controller + parameter name, and one where you provide route name + parameter name. ParameterName is the name of the parameter name of your action method which will receive the value to validate.

Here’s the RemoteAttributeAdapter class:

using System.Collections.Generic;
using System.Web.Mvc;  

public class RemoteAttributeAdapter : DataAnnotationsModelValidator<RemoteAttribute>
{
    public RemoteAttributeAdapter(ModelMetadata metadata,
                                  ControllerContext context,
                                  RemoteAttribute attribute) :
        base(metadata, context, attribute) { }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        ModelClientValidationRule rule = new ModelClientValidationRule()
            {
                ErrorMessage = ErrorMessage,
                ValidationType = "remote"
            };
        rule.ValidationParameters["url"] = Attribute.GetUrl(ControllerContext);
        rule.ValidationParameters["parameterName"] = Attribute.ParameterName;
        return new ModelClientValidationRule[] { rule };
    }
}

This a DataAnnotations validator adapter which enables the client-side validation support on the server side (say that 3x fast). The purpose of this class is to tell the DataAnnotations validation system what to emit into the client-side JavaScript when it finds one of these validator attributes. The values it's emitting are based on the JavaScript file we wrote above: a rule named remote, which has two parameters: url and parameterName.

You will need to register this adapter in your Global.asax file, in the Application_Start() method, by calling:

DataAnnotationsModelValidatorProvider.RegisterAdapter(
    typeof(RemoteAttribute),
    typeof(RemoteAttributeAdapter)
);

Putting It All Together

Let's start with a model that uses remote validation:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

public class RemoteModel
{
    [Required]
    [DisplayName("Any Number")]
    public int AnyNumber { get; set; }

    [Required]
    [Remote("IsOdd", "Sample", "value",
            ErrorMessage = "Value for '{0}' is not odd.")]
    [DisplayName("Odd Number")]
    public int OddNumber { get; set; }
}

And the controller:

using System;
using System.Web.Mvc;

public class SampleController : Controller
{
    public string IsOdd(int value)
    {
        return ((value % 2) == 1) ? "true" : "false";
    }

    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(RemoteModel model)
    {
        return View(model);
    }
}

And the view:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="ViewPage<RemoteModel>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <p>
        Server thinks the model
        <b><%= ViewData.ModelState.IsValid ? "IS" : "IS NOT" %></b>
        valid.
    </p>
    <% using (Html.BeginForm()) { %>
        <%= Html.EditorForModel() %>
        <input type="submit" />
    <% } %>
</asp:Content>

When we fire up the page, we’ll see two editor boxes (for “Any Number” and “Odd Number”). If we click submit, we will immediately see via client-side validation that the values are not valid because they are required.

You can tell it's client-side validation, because the browser “busy” icon never spins, the page doesn't flash, and the sentinel at the top will tell you that the server still thinks your model is valid. If it looks you're still posting to the server, make sure you’ve included all 3 JavaScript files as well as called <% Html.EnableClientValidation(); %> somewhere in your view or master page.

Now type “1” into “Any Number”, and “2” into “Odd Number”, then tab away to the “Submit Query” button (don’t click it yet). The remote validation will fire and quickly you’ll see an error next to “Odd Number” which says “Value for 'Odd Number' is not odd.”.

Now take note that you can still click Submit Query, and it will still submit up to the server (as I alluded to above). More interestingly, though, is that the error went away from next to “Odd Number”. That’s because our [Remote] attribute doesn’t do any server-side validation. We could re-write it to execute the entire action and get the result, but that just seems too heavy-weight.

Instead, let’s write a new attribute which derives from RemoteAttribute:

using System;

[AttributeUsage(AttributeTargets.Property)]
public class OddNumberAttribute : RemoteAttribute
{
    public OddNumberAttribute()
        : base("IsOdd", "Sample", "value")
    {
                    ErrorMessage = "{0} must be odd.";
    }

    public override bool IsValid(object value)
    {
        if (value == null)
           return true;

        int intValue;
        if (!Int32.TryParse(value.ToString(), out intValue))
           return false;
 
        return IsOdd(intValue);
    }

    public static bool IsOdd(int value)
    {
        return ((value % 2) == 1);
    }
}

Note that we've moved our “complex logic” into the OddNumberAttribute as a static. Normally we’d probably already have isolated this logic somewhere else in our class hierarchy, but this was a convenient place for it to in the sample. The important point is that this code is reachable both from within the new attribute, as well as from the controller, because we’re going to re-write the IsOdd action on our controller to call the same logic now:

public string IsOdd(int value)
{
    return OddNumberAttribute.IsOdd(value) ? "true" : "false";
}

We update our model to use the new attribute instead of the old Remote attribute:

[Required]
[OddNumber]
[DisplayName("Odd Number")]
public int OddNumber { get; set; }

And one last change to our registration code in global.asax:

DataAnnotationsModelValidatorProvider.RegisterAdapter(
    typeof(OddNumberAttribute),
    typeof(RemoteAttributeAdapter)
);

Now back to our form, and this time when we try to submit a value with a non-odd number, the server will tell us we made a mistake. We'll get a round-trip and a flash of content, but now Odd Number will still be invalid, and our little sentinel on the top says that "Server thinks the model IS NOT valid." now.

What is so SPECIAL on ASPHostDirectory.com ASP.NET MVC Hosting?

We know that finding a cheap, reliable web host is not a simple task so we’ve put all the information you need in one place to help you make your decision. At ASPHostDirectory, we pride ourselves in our commitment to our customers and want to make sure they have all the details they need before making that big decision.

We will work tirelessly to provide a refreshing and friendly level of customer service. We believe in creativity, innovation, and a competitive spirit in all that we do. We are sound, honest company who feels that business is more than just the bottom line. We consider every business opportunity a chance to engage and interact with our customers and our community. Neither our clients nor our employees are a commodity. They are part of our family.

The followings are the top 10 reasons you should trust your online business and hosting needs to us:

- FREE domain for Life - ASPHostDirectory gives you your own free domain name for life with our Professional Hosting Plan and 3 free domains with any of Reseller Hosting Plan! There’s no need to panic about renewing your domain as ASPHostDirectory will automatically do this for you to ensure you never lose the all important identity of your site
- 99,9% Uptime Guarantee - ASPHostDirectory promises it’s customers 99.9% network uptime! We are so concerned about uptime that we set up our own company to monitor people’s uptime for them called ASPHostDirectory Uptime
- 24/7-based Support - We never fall asleep and we run a service that is opening 24/7 a year. Even everyone is on holiday during Easter or Christmast/New Year, we are always behind our desk serving our customers
- Customer Tailored Support - if you compare our hosting plans to others you will see that we are offering a much better deal in every aspect; performance, disk quotas, bandwidth allocation, databases, security, control panel features, e-mail services, real-time stats, and service
- Money Back Guarantee - ASPHostDirectory offers a ‘no questions asked’ money back guarantee with all our plans for any cancellations made within the first 30 days of ordering. Our cancellation policy is very simple - if you cancel your account within 30 days of first signing up we will provide you with a full refund
- Experts in ASP.NET MVC Hosting - Given the scale of our environment, we have recruited and developed some of the best talent in the hosting technology that you are using. Our team is strong because of the experience and talents of the individuals who make up ASPHostDirectory
- Daily Backup Service - We realise that your website is very important to your business and hence, we never ever forget to create a daily backup. Your database and website are backup every night into a permanent remote tape drive to ensure that they are always safe and secure. The backup is always ready and available anytime you need it
- Easy Site Administration - With our powerful control panel, you can always administer most of your site features easily without even needing to contact for our Support Team. Additionally, you can also install more than 100 FREE applications directly via our Control  Panel in 1 minute!

Happy Hosting!



ASPHostDirectory ASP.NET MVC Hosting :: Turn on Compile-Time View Checking

clock October 7, 2010 04:53 by author Darwin

We like the compiler to catch as many errors as possible before we start debugging or release our application. This also applies to code nuggets in ASP.NET MVC views, especially since these are not easily unit-testable. But views are not validated at compilation, at least not when using the standard settings for ASP.NET MVC projects.

Tools like Resharper can notify you of syntax errors within your views, but you can still build the project and not get a single error. Instead, your application will crash when trying to evaluate the buggy view.

Fortunately you can easily make Visual Studio compile your views along with the rest of your code. The only downside is that your project will build a bit slower, but if this bothers you during development you can also enable this feature on a per configuration basis. For example you may want to compile your views in Release mode, but not in your Debug configuration , so you have the extra safety of compile-time view checking before releasing a new version, but you still get lightning-fast compilation times while developing.

Please proceed as follows to turn on compile time view compilation:

1. Open your .csproject or .vbproject file in a text editor of your choice. It’s just a simple xml file, which is why any editor will do fine.

2. Locate the <PropertyGroup> element that belongs to the configuration you would like to alter.

3. Within this PropertyGroup, add an additional element with “true” as its text value.

For example, this will turn on view compilation in my project’s Release configuration:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
 <MvcBuildViews>true</MvcBuildViews>
...

That’s it! The next time one of your views has compile-time errors, these will be reported when building your application.

One last thing: You need to repeat this procedure for all configurations you might create in the future if you want your views to be checked in those configurations as well. Even if you tell Visual Studio to copy settings from an existing configuration where this tag is already set to true, the MvcBuildViews tag is not copied by Visual Studio.

What is so SPECIAL on ASPHostDirectory.com ASP.NET MVC Hosting?

We know that finding a cheap, reliable web host is not a simple task so we’ve put all the information you need in one place to help you make your decision. At ASPHostDirectory, we pride ourselves in our commitment to our customers and want to make sure they have all the details they need before making that big decision.

We will work tirelessly to provide a refreshing and friendly level of customer service. We believe in creativity, innovation, and a competitive spirit in all that we do. We are sound, honest company who feels that business is more than just the bottom line. We consider every business opportunity a chance to engage and interact with our customers and our community. Neither our clients nor our employees are a commodity. They are part of our family.

The followings are the top 10 reasons you should trust your online business and hosting needs to us:

- FREE domain for Life - ASPHostDirectory gives you your own free domain name for life with our Professional Hosting Plan and 3 free domains with any of Reseller Hosting Plan! There’s no need to panic about renewing your domain as ASPHostDirectory will automatically do this for you to ensure you never lose the all important identity of your site
- 99,9% Uptime Guarantee - ASPHostDirectory promises it’s customers 99.9% network uptime! We are so concerned about uptime that we set up our own company to monitor people’s uptime for them called ASPHostDirectory Uptime
- 24/7-based Support - We never fall asleep and we run a service that is opening 24/7 a year. Even everyone is on holiday during Easter or Christmast/New Year, we are always behind our desk serving our customers
- Customer Tailored Support - if you compare our hosting plans to others you will see that we are offering a much better deal in every aspect; performance, disk quotas, bandwidth allocation, databases, security, control panel features, e-mail services, real-time stats, and service
- Money Back Guarantee - ASPHostDirectory offers a ‘no questions asked’ money back guarantee with all our plans for any cancellations made within the first 30 days of ordering. Our cancellation policy is very simple - if you cancel your account within 30 days of first signing up we will provide you with a full refund
- Experts in ASP.NET MVC Hosting - Given the scale of our environment, we have recruited and developed some of the best talent in the hosting technology that you are using. Our team is strong because of the experience and talents of the individuals who make up ASPHostDirectory
- Daily Backup Service - We realise that your website is very important to your business and hence, we never ever forget to create a daily backup. Your database and website are backup every night into a permanent remote tape drive to ensure that they are always safe and secure. The backup is always ready and available anytime you need it
- Easy Site Administration - With our powerful control panel, you can always administer most of your site features easily without even needing to contact for our Support Team. Additionally, you can also install more than 100 FREE applications directly via our Control  Panel in 1 minute!

Happy Hosting!