LinqToSql Count

You can pass the results of a linq query to the next statement like this one

var q = context.Products
                .Where(p => p.ProductName.StartsWith(“A”))
                .Count();
and that should provide the count of products with names starting with “A”. 
Further it would make no difference (performance wise) to skip theWhere statement and simply call the Count with filter as parameter, like:
var q = context.Products
                .Count(p => p.ProductName.StartsWith(“B”));
or in another syntax like:
    q = (from p in context.Products
         where p.ProductName.StartsWith(“C”)
         select true).Count();
So, I did put a tracing into the Context.Log to see what it goes to the SQL-Server. I’ve got the following for all three cases:
SELECT COUNT(*) AS [value]
FROM [dbo].[Products] AS [t0]
WHERE [t0].[ProductName] LIKE @p0
— @p0: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [A%]
— Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

Placing a Web Method in a Page

In most cases, it makes sense to create a separate web service to handle your ASP.NET AJAX callbacks.
This approach generally results in clearer pages and makes it easier to debug and refine your code.
However, in some situations you may decide you have one or more web methods that are designed
explicitly for use on a single page and that really shouldn’t be reused in other parts of the application. In
this case, you may choose to create a dedicated web service for each page, or you might choose to move
the web service code into the page.
Placing the web method code in the page is easy—in fact, all you need is a simple bit of cut-andpaste.
First, copy your web method (complete with the WebMethod attribute) into the code-behind class
for your page. Then, change it to a static method, and add the System.Web.Script.Services.ScriptMethod
attribute. Here’s an example where the web method (named GetTerritoriesInRegion) is placed in a web
page named WebServiceCallback_PageMethods:
public partial class WebServiceCallback_PageMethods : System.Web.UI.Page
{
   [System.Web.Services.WebMethod()]
   [System.Web.Script.Services.ScriptMethod()]
   public static List<Territory> GetTerritoriesInRegion(int regionID)
   {
      // Farm the work out to the web service class.
      TerritoriesService service = new TerritoriesService();
      return service.GetTerritoriesInRegion(regionID);
   }
}
Next, set the ScriptManager.EnablePageMethods property to true, and remove the reference in the
<Services> section of the ScriptManager (assuming you don’t want to use any non-page web services):

<asp:ScriptManager ID=”ScriptManager1″ runat=”server” EnablePageMethods=”true”>
</asp:ScriptManager>
Finally, change your JavaScript code so it calls the method through the PageMethods object, as
shown here:

PageMethods.GetTerritoriesInRegion(regionID, OnRequestComplete, OnError);

The PageMethods object exposes all the web methods you’ve added to the current web page.
One advantage of placing a web method in a page is that the method is no longer exposed through
an .asmx file. As a result, it’s not considered part of a public web service, and it’s not as easy for someone
else to discover. This is appealing if you’re trying to hide your web services from curious users.
Another reason you might choose to code your web methods in the page class is to read values from
view state or the controls on the page. When you trigger a page method, a stripped-down version of the
page life cycle executes, just like with the ASP.NET client callback feature you saw in Chapter 29. Of
course, there’s no point in trying to modify page details because the page isn’t being rerendered, so any
changes you make will simply be discarded.

Loading a custom control at runtime

You can load a server control to your page using the constructor of the control. For example a Literal control can be loaded as follows:

plhContainer.Controls.Add(
new Literal
{
Text = string.Format("{0}.{1}",
method.ReflectedType.FullName, method.Name)
});

When it comes to a custom control you also want the markup code of you custom control to be loaded too. So you need to tell the Page o load it for you:


var nameBox = (NameBox) Page.LoadControl("NameBox.ascx");

Basically, you could do this at any time, but it is recommanded to do this at Page_Load the reason is that this is the best place for the control to restore its state and receive postback events. Also the binding will take place after this method. Look at my previous post for the sequence of the events and method calls when page gets loaded.
It is also recomannded to set a unique ID to that control if you need to find that later using FindControl, or some one else want to find where you have put it 🙂

So, my load method will look like this:


private void LoadMyControls()
{
var nameBox = (NameBox) Page.LoadControl("NameBox.ascx");
// Give the user control a unique name by setting its ID property.
// You can use this information to retrieve a reference to the control
// when you need it with the Page.FindControl() method.
nameBox.ID = "nameBox";
nameBox.FirstName = "Asghar";
nameBox.LastName = "Panahy";
nameBox.ChangeRequest += ChangeName;
plhContainer.Controls.Add(nameBox);
}

When I call LoadMyControls() in Page_Load method, I see the following sequence in my output:


STARTING: MCTS._70_515.Resources._Default.Page_Init
STARTING: MCTS._70_515.Resources._Default.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources._Default.OnLoad
STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources._Default.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload
STARTING: MCTS._70_515.Resources._Default.OnUnload

Notice that the custom control gets its data binded just after the page has passed Loading which is a good thing.

ASP Page en Control Lifecycle

When I put a logging in a couple of override methods of a NameBox control and load the page containing the custom control I see the following:

STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload

It is important to note that Page_Load is long before OnLoad method, similar to Page_Init versus OnInit.

Next I click on the change button to post back to handle the event and I see the following:

STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources.NameBox.ChangeRequestClicked
STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload

Next, I add some similar loggging to the page that contains the control and see what happens when I load the page:


STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Init
STARTING: MCTS._70_515.Resources._Default.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Load
STARTING: MCTS._70_515.Resources._Default.OnLoad

STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources._Default.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload
STARTING: MCTS._70_515.Resources._Default.OnUnload

So, The OnLoad method gets called after binding whereas the Page_Load is about before the binding. Obviously, if you need to initialize your data, you better put your code in OnInit rather that OnLoad or Page_Load.
Another important thig here is the PreRender methods. These methods get called after load has been completed and the data is assumed to be in place.

Now let’s see what happens when I click a button on the control which causes a postback:


STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Init
STARTING: MCTS._70_515.Resources._Default.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Load
STARTING: MCTS._70_515.Resources._Default.OnLoad

STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources.NameBox.ChangeRequestClicked
STARTING: MCTS._70_515.Resources._Default.ChangeName
STARTING: MCTS._70_515.Resources._Default.OnPreRender

STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload
STARTING: MCTS._70_515.Resources._Default.OnUnload

Both event handlers in the control and in the page are called after all controls and the page has been loaded and the data is binded too, just before the rendering take place.

Notify Database changes to ASP.NET pages

In the old times there were two ways of getting notifications from the database into the ASP.NET pages.

  1. writing to a file (simply create or delete an empty file) in a specific location where a CacheDependency can listen to and callBack a method on change.
  2. implement an HttpHandler that gets the notification with a parameter of what is changed, and let the database send an http request to the IIS server on a trigger.
I am sure there could be worse methods but even these two have a lot of complications in a secured architecture with high performance requirements, like we have these days.

Fortunately, since SQL-Servet 2000, there is a new component implemented into SQL-server called Service Broker that act on changes in tables that are marked to be notified on change. Internally they write to a specific table mentioning about the change.
In order to configure a database for Service Broker you can call a statement like this:
Use Northwind
ALTER DATABASE Northwind SET ENABLE_BROKER
For more information about Service Broker see the MSDN.
Next, you need to set the ASP.NET to recieve the notification via dependencies. To do so , you need to add the command object to the dependency:
// Create the dependency.
SqlCacheDependency empDependency = new SqlCacheDependency(cmd);
// Add a cache item that will be invalidated if one of its records changes
// (or a new record is added in the same range).

Cache.Insert("Employees", ds, empDependency);
To start the notification on application service you need to add the following to the Global.ascx.cs in Application_Start
SqlDependency.Start(connectionString);
It is a good practice to stop the notifications on Application_End
SqlDependency.Stop(connectionString);
Once this is implemented, you can get the notifications through the OnChange event of the SqlDependency class.

Implementing custom FileCacheProvider

This is a summerized version of what you can find in the APress book Chapter 11.

If you want to cach some pages or all, you need to first tell the ASP.NET to do so. As the caching starts before rendering the page, you can not specifiy this in the page markup, rather it will be mentioned in the Global.asax.cs
        public override string GetOutputCacheProviderName(HttpContext context)
        {
            // Get the page.
            string pageAndQuery = System.IO.Path.GetFileName(context.Request.Path);
            if (pageAndQuery.StartsWith(“OutputCaching.aspx”))
                return “FileCache”;
            else
                return base.GetOutputCacheProviderName(context);
        }
This tells to ASP.NET to use FileCache mechanics for cachin OutputCaching.aspx page. The rest will just follow the default.
Next step is to specify where to find the implementation of FileCache. This is mentioned in the web.config as follows:
    <system.web>
      <caching>
      <outputCache defaultProvider=”FileCache”>
        <providers>
          <add name=”FileCache” type=”MyCompany.MyProject.Caching.FileCacheProvider” 
               cachePath=”~/Cache” />
        </providers>
      </outputCache>
    </caching>
  </system.web>
Notice that the cachePath is not a recognized attribute but we may introduce it to get the parameters. In this case it refers to an existing folder on the root of the website.
Next step is to implement the provider. This involves to implement a class that inherits from OutputCacheProvider and overrides the methods as follows:
    public class FileCacheProvider : OutputCacheProvider
    {
        // The location where cached files will be placed.
        public string CachePath
        { get; set; }
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection attributes)
        {
            base.Initialize(name, attributes);
            // Retrieve the web.config settings.
            CachePath = HttpContext.Current.Server.MapPath(attributes[“cachePath”]);
        }
        public override object Add(string key, object entry, System.DateTime utcExpiry)
        {
            // Transform the key to a unique filename.
            string path = ConvertKeyToPath(key);
            // Set it only if it is not already cached.
            if (!File.Exists(path))
            {
                Set(key, entry, utcExpiry);
            }
            return entry;
        }
        public override object Get(string key)
        {
            string path = ConvertKeyToPath(key);
            if (!File.Exists(path)) return null;
            CacheItem item = null;
            using (FileStream file = File.OpenRead(path))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                item = (CacheItem)formatter.Deserialize(file);
            }
            // Remove expired items.
            if (item.ExpiryDate <= DateTime.Now.ToUniversalTime())
            {
                Remove(key);
                return null;
            }
            return item.Item;
        }
        public override void Set(string key, object entry, System.DateTime utcExpiry)
        {
            CacheItem item = new CacheItem(entry, utcExpiry);
            string path = ConvertKeyToPath(key);
            // Overwrite it, even if it already exists.
            using (FileStream file = File.OpenWrite(path))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(file, item);
            }
        }
        public override void Remove(string key)
        {
            string path = ConvertKeyToPath(key);
            if (File.Exists(path)) File.Delete(path);
        }
        private string ConvertKeyToPath(string key)
        {
            // Flatten it to a single file name, with no path information.
            string file = key.Replace(‘/’, ‘-‘);
            // Add .txt extension so it’s not confused with a real ASP.NET file.
            file += “.txt”;
            return Path.Combine(CachePath, file);
        }
    }
The CachePath will be set by configurationManager. The private method ConvertKeyToPath helps to find a unique filename based on the url. This example uses binary formatter and a wrapper class that adds an expiration property to any object that needs to be cached. So, the following is the implementation of the wrapper class:
    [Serializable]
    public class CacheItem
    {
        public DateTime ExpiryDate;
        public object Item;
        public CacheItem(object item, DateTime expiryDate)
        {
            ExpiryDate = expiryDate;
            Item = item;
        }
    }
That’s all. When you run this you will notice that you will get an error if the Cache folder does not exist in the root.
To test the caching try to put the next code in the Default.aspx
    <%@ OutputCache Duration=”10″ VaryByParam=”None” %>

MVC Tips

You can use the standard ASP.NET features in your MVC views. In this case, you call the String.Format method to display the UnitPrice field in a suitable form for a monetary amount. You just pass in the Model.UnitPrice value as the argument to the method call.
<%= String.Format(“{0:F2}”, Model.UnitPrice) %>

String class can also be used as a formatter in thextbox:

Unit Price:
<%: Html.TextBoxFor(model => model.UnitPrice, new {Value = String.Format(“{0:F2}”, Model.UnitPrice)})%>

Localizing ASP.NET Tips

There are two kind of localizations:

  • Local resources are specific to a page.
  • Global resources are shared throughout the site

If your site contains many folders, you might have an App_LocalResources subfolder in each folder of your site.

<asp:Button ID="ButtonFind" runat="server" Text="Find" CssClass="submitButton" meta:resourcekey="ButtonFindResource1" />

<asp:Localize ID="LabelTitle" runat="server" Text="Customer Lookup" meta:resourcekey="LabelTitleResource1"></asp:Localize>

The Text property of the Button control is to aid the developer at design time.

ASP.NET will use the key to find and match on any property that might be set inside the resource file as meta:resourcekey.<PropertyName> or ButtonFindResoure1.Text:

<data name="ButtonFindResource1.Text" xml:space="preserve">

     <value>Find</value>

</data>

<data name="ButtonFindResource1.Tooltip" xml:space="preserve">

     <value>Click this to start the search action</value>

</data>

Accessing a Local resource in C# could be done as follows:

Textbox1.Text = GetLocalResourceObject(“Textbox1.Text”).ToString();

Accessing a shared global resource in C# could be done in one of the two followings:

Textbox1.Text = Resources.ResourceFileName.Textbox1Text;

Textbox1.Text = GetGlobalResourceObject(“ResourceFileName”, “Textbox1Text”) as string;

The methods GetGlobalResourceObject  and GetLocalResourceObject can come handy when the resources does not exist at compile time and might be provided as a separate dll at runtime.

Show an object instance as an xnl on your page

This sample code demonstrates how to show an instance of an object in XML format on a page. It encodes the xml serialized string and dumps it as a code into a placeholder.
    public void ShowXmlObject<T>( T instance)
    {
        var ms = new MemoryStream();
        System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(ms, Encoding.Unicode);
        var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
        serializer.Serialize(writer, instance);
        writer.Flush();
        ms.Position = 0;
        var reader = new StreamReader(ms);
        LogCode(HttpUtility.HtmlEncode(IndentXml(reader.ReadToEnd())));
    }
    public string IndentXml(string xml)
    {
        var p = xml.LastIndexOf(“?>”);
        if (p > 0)
            xml = xml.Substring(p + 2);
        var doc = new System.Xml.XmlDocument();
        doc.LoadXml(xml);
        var settings = new System.Xml.XmlWriterSettings();
        settings.Indent = true;
        settings.IndentChars = ”  “;
        settings.NewLineChars = “rn”;
        settings.NewLineHandling = System.Xml.NewLineHandling.None;
        var  sbOutput = new StringBuilder();
        var writer = System.Xml.XmlWriter.Create(sbOutput, settings);
        doc.Save(writer);
        writer.Close();
        return sbOutput.ToString();
    } 
    public void LogCode(string message)
    {
        placeResult.Controls.Add(new Literal() { Text = "<pre><code>" + message + "</code></pre>" });
    }

Show Items structure in Sitecore

The following example demonstrates how to get the information about a node on the back side of a node by giving the item.ID. You also could do it easier by having the full path instead of creating an ID.
It is important to do all this inside a SecurityDisabler. You might have some nodes that are not accessible to anonymous user, if the code is running for without proper security.
    protected void StartToAnalyse(object sender, EventArgs e)    {
        Sitecore.Data.Database master =
            Sitecore.Configuration.Factory.GetDatabase(“master”);
        using (new Sitecore.SecurityModel.SecurityDisabler())
        {
             ProcessItem(master.GetItem(new Sitecore.Data.ID(textboxRoot.Text)));
        }
    }
    private void ShowTechnicalDetails(Sitecore.Data.Items.Item item)
    {
        string pageName = item.DisplayName;
        
        var template = item.Template;
        //LogLine(” Template : ” + item.TemplateName);
        // LogLine(” Uri : ” + item.Uri.Path);
        // string rend = Sitecore.Context.Item.Fields[“Renderings”].Value;
        Sitecore.Data.Items.DeviceItem defDevice = Sitecore.Data.Items.DeviceItem.ResolveDevice(Sitecore.Configuration.Factory.GetDatabase(“master”));
        var layout = item.Visualization.GetLayout(defDevice);
        if (layout != null)
        {
            LogLine(” Layout : <u> [“ + layout.DisplayName + “]</u>” );
        //   //  LogLine(” File : ” + layout.FilePath);
        }
        var renderings = item.Visualization.GetRenderings(defDevice, false);
        //LogLine(“Renderings:<ul>”);
        foreach(var rend in renderings)
        {
            //LogLine(” Layout : ” + rend.RenderingItem.DisplayName);
            LogItem(pageName + “;” + rend.RenderingItem.InnerItem[“Path”]);
        }
    }
    private void ProcessItem(Sitecore.Data.Items.Item item)
    {
        if (item == null)
        {
            LogLine(“Item not found.”);
            return;
        }
        
        ShowTechnicalDetails(item);
        foreach (Sitecore.Data.Items.Item child in item.Children)
        {
            ProcessItem(child);
        }
    }