MVC Stories

Hi All,

Been a while since I've writen some posts, been pretty hectic hours at work and weekends building a house so my chances to blog have been limited.

I intend over the coming few days to give a few tips and tricks on MCV2.

Here's on gottya..

Be carefull how you name your formal arguements in your controller functions.

You can see from the screenshot below that I created two args, "Name" and "name"

By default the first matching case insensitive value will be applied to both variables by MVC...

Usually this will be avoided by good naming conventions but be carefull nonetheless :-)

 

 

WCF 4.0 File-less Activation (.svc less)


http://url/abc.svc  .svc at the end of url makes it user unfriendly. It also makes it Low REST service as it donot follow the REST URI principle.

Till date developers have to overcome this limitation by implementing URLReWrite module in IIS.
Writing custom code to implement this is error prone and needs maintenance over a period. WCF 4.0 has introduced
a feature to access WCF services using attribute called as relativeAddress.
Following .config setting depicts how a Calculat

orService can be accessed using relative URL.

<system.serviceModel>

    <serviceHostingEnvironment>

      <serviceActivations>

        <add relativeAddress="/Payment" service=“CalculatorService.svc"/>

      </serviceActivations>

    </serviceHostingEnvironment>

  </system.serviceModel>

 

**UPDATE

I've just tried to do this in an application I was working on, don't know where I got my origional information from but this Fileless activation was not what was advertised at the time, it requires a .svc extension on the url without the need for for a .svc physical file.

I've accomplished my restful approach with routing.

 

Output and Encoding in ASP.net 4.0

Pre .NET 4.O

Prior to  ASP.NET 4.0 (and especially with MVC) when a user outputted information to a webpage they used <%= Server.HtmlEncode(modelViewStore.Content) %>

The reason for the Encoding is primiarily to prevent XSS (cross site script injection) whereby someone may try to inject some client side script or HTML Markup to vandalize a site or to steal valuable information.

This approach has a few shortcommings; like,

* Users may forget the encoding
* bit verbose

 


.NET 4.0

A new nugged has arrived:

<%: modelViewStore.Content %>

WaitCursor and MVVM

Ever wondered how to display the correct cursor in an application that is databinded to async methods?

Pretty easy solution, just databind the cursor on the window itself.

Here's how:

  • Add an IsBusy property on the DataContext (and implement INotifyPropertyChanged on it)
  • Add the following to your window xaml

[code:c#]

xmlns:valueConverters="clr-namespace:XXX.ValueConverters"
Cursor="{Binding IsBusy, Converter={valueConverters:CursorExtensionConverter}}" 

[/code]

 

  • Create the following ValueConverter

[code:c#]

public class CursorExtensionConverter : MarkupExtension, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value != null && ((bool)value))
            return Cursors.Wait;           
        else
            return Cursors.Arrow;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return instance;
    }

    private static CursorExtensionConverter instance = new CursorExtensionConverter();
}

[/code]

 

Note: Use of MarkupExtension

 

INotifyPropertyChanged diagnostics

Those of you that use INotifyPropertyChanged may have noticed it's easy to break the code if you choose to refactor/rename as the property name string does not get refactored.

Here is a mechanism to catch this problem at the implementation stage.

 

[code:c#]

#region Debugging Aides

/// <summary>
/// Warns the developer if this object does not have
/// a public property with the specified name. This
/// method does not exist in a Release build.
/// </summary>
[Conditional("DEBUG")]
[DebuggerStepThrough]
public void VerifyPropertyName(string propertyName)
{
    // Verify that the property name matches a real, 
    // public, instance property on this object.
    if (TypeDescriptor.GetProperties(this)[propertyName] == null)
    {
        string msg = "Invalid property name: " + propertyName;

        if (this.ThrowOnInvalidPropertyName)
            throw new Exception(msg);
        else
            Debug.Fail(msg);
    }
}

/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail() is used
/// when an invalid property name is passed to the VerifyPropertyName method.
/// The default value is false, but subclasses used by unit tests might
/// override this property's getter to return true.
/// </summary>
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

#endregion // Debugging Aides

#region INotifyPropertyChanged Members

/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged = (s, e) => { };

/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName">The property that has a new value.</param>
protected virtual void OnPropertyChanged(string propertyName)
{
    this.VerifyPropertyName(propertyName);
    this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));           
}

#endregion // INotifyPropertyChanged Members

[/code]

WPF ListViewItem Commands with MVVM pattern

If you're interested to see how to attach commands to listview items for use with an implementation of the MVVM pattern, have a look at this.

 

[code:c#]

<Style x:Key="Local_OpenEntityStyle"
           TargetType="{x:Type ListViewItem}">
        <Setter Property="acb:CommandBehavior.Event"
                        Value="MouseDoubleClick" />
        <Setter Property="acb:CommandBehavior.Command"
                        Value="{Binding ElementName=uiEntityListDisplay, Path=DataContext.OpenEntityCommand}" />
        <Setter Property="acb:CommandBehavior.CommandParameter"
                        Value="{Binding}" />
</Style>

[/code]

 

Here the command to be fired on the MouseDoubleClick event is set, the CommandParameter, will be the data object that we click on.

Windows special folders enum


Ever want to find out from c# where some "special" folders are located so you can use them in your desktop application?

Here's how.

[code:c#]

Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)


[/code]

 

See  Environment.SpecialFolder enumeration for more locations.

Exposing OData with WCF Ria Services 4.0

I was just about to write up a little blog on the how and why of Exposing OData (Open Data Protocol) in WCF 4.0.
But seeming it being a Bank Holiday and, if you follow any of my posts, you'll know I don't spend a lot of time writing them up, they are more like mini blogs Laughing

So I found this excellent article by Brad Abrams

http://blogs.msdn.com/brada/archive/2010/03/16/silverlight-4-ria-services-ready-for-business-exposing-odata-services.aspx

I recommend you have a read because if you've never encounted OData before you'll be amazed how easy it is to expose and consume your domain service (expecially with Excel 2010)

Preserving ListView state

Xaml Serialization to the rescue.

The following sample code will persist the current Listview state to disk and restore it the next time the control is loaded.

[code:c#]

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        Loaded="OnLoaded"
        >
    <Grid>
        <Border x:Name="bdr">
        <ListView x:Name="lvTest" Initialized="lvInit">
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="140" Header="Column 1" />
                    <GridViewColumn Width="140" Header="Column 2" />
                    <GridViewColumn Width="140" Header="Column 3" />
                </GridView>
            </ListView.View>
        </ListView>
        </Border>
    </Grid>
</Window>
 

[/code]

Code behind 

[code:c#]

using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void lvInit(object sender, EventArgs e)
        {
            GridView gv = lvTest.View as GridView;
            gv.Columns.CollectionChanged += (s, gvE) =>
            {
                if (gvE.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Move)
                {
                    SaveState();
                }
            };

        }


        private void SaveState()
        {
            string lvXaml = XamlWriter.Save(lvTest);
            using (var s = new StreamWriter(@"c:\temp\lv.xaml"))
            {
                s.Write(lvXaml);
            }
        }
              
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            ListView li = null;
            if (File.Exists(@"c:\temp\lv.xaml"))
                bdr.Child = (ListView)XamlReader.Load(File.OpenRead(@"c:\temp\lv.xaml"));           
        }

       
    }
}

[/code]

Linq to Xlsx

A sample how to read a Excel 2007/2010 using Open XML SDK V2

(forgive the bad syntax highlighting)

 

[code:c#]

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Packaging;

namespace ConsoleApplicationLinqToXlsx
{
    class Program
    {
        static void Main(string[] args)
        {
            //Declare variables to hold refernces to Excel objects.
            Workbook workBook;
            SharedStringTable sharedStrings;
            IEnumerable<Sheet> workSheets;
            WorksheetPart custSheet;
            WorksheetPart orderSheet;

            //Declare helper variables.
            string custID;
            string orderID;
            List<Customer> customers;
            List<Order> orders;

            //Open the Excel workbook.
            using (SpreadsheetDocument document =
              SpreadsheetDocument.Open(@"d:\Temp\ConsoleApplicationLinqToXlsx\TestOpenXMl.xlsx ", true))
            {
                //References to the workbook and Shared String Table.
                workBook = document.WorkbookPart.Workbook;
                workSheets = workBook.Descendants<Sheet>();
                sharedStrings =
                  document.WorkbookPart.SharedStringTablePart.SharedStringTable;

                //Reference to Excel Worksheet with Customer data.
                custID =
                  workSheets.First(s => s.Name == @"Customer").Id;
                custSheet =
                  (WorksheetPart)document.WorkbookPart.GetPartById(custID);

                //Load customer data to business object.
                customers =
                  Customer.LoadCustomers(custSheet.Worksheet, sharedStrings);

                //Reference to Excel worksheet with order data.
                orderID =
                  workSheets.First(sheet => sheet.Name == @"Order").Id;
                orderSheet =
                  (WorksheetPart)document.WorkbookPart.GetPartById(orderID);

                //Load order data to business object.
                orders =
                  Order.LoadOrders(orderSheet.Worksheet, sharedStrings);

                //List all customers to the console.
                //Write header information to the console.
                Console.WriteLine("All Customers");
                Console.WriteLine("{0, -15} {1, -15} {2, -5}",
                  "Customer", "City", "State");

                //LINQ Query for all customers.
                IEnumerable<Customer> allCustomers =
                    from customer in customers
                    select customer;

                //Execute query and write customer information to the console.
                foreach (Customer c in allCustomers)
                {
                    Console.WriteLine("{0, -15} {1, -15} {2, -5}",
                      c.Name, c.City, c.State);
                }
                Console.WriteLine();
                Console.WriteLine();


                //Write all orders over $100 to the console.
                //Write header information to the console.
                Console.WriteLine("All Orders over $100");
                Console.WriteLine("{0, -15} {1, -10} {2, 10} {3, -5}",
                  "Customer", "Date", "Amount", "Status");

                //LINQ Query for all orders over $100.
                //Join used to display customer information for the order.
                var highOrders =
                  from customer in customers
                  join order in orders on customer.Name equals order.Customer
                  where order.Amount > 100.00
                  select new
                  {
                      customer.Name,
                      order.Date,
                      order.Amount,
                      order.Status
                  };

                //Execute query and write information to the console.
                foreach (var result in highOrders)
                {
                    Console.WriteLine("{0, -15} {1, -10} {2, 10} {3, -5}",
                      result.Name, result.Date.ToShortDateString(),
                      result.Amount, result.Status);
                }
                Console.WriteLine();
                Console.WriteLine();


                //Report on customer orders by status.
                //Write header information to  the console.
                Console.WriteLine("Customer Orders by Status");

                //LINQ Query for summarizing customer order information by status.
                //There are two LINQ queries. 
                //Internal query is used to group orders together by status and
                //calculates the total order amount and number of orders.
                //External query is used to join Customer information.
                var sumoforders =
                  from customer in customers
                  select new
                  {
                      customer.Name,
                      statusTotals =
                          from order in orders
                          where order.Customer == customer.Name
                          group order.Amount by order.Status into statusGroup
                          select new
                          {
                              status = statusGroup.Key,
                              orderAmount = statusGroup.Sum(),
                              orderCount = statusGroup.Count()
                          }
                  };

                //Execute query and write information to the console.
                foreach (var customer in sumoforders)
                {
                    //Write Customer name to the console.
                    Console.WriteLine("-{0}-", customer.Name);
                    foreach (var x in customer.statusTotals)
                    {
                        Console.WriteLine("  {0, -10}: {2,2} orders totaling {1, 7}",
                          x.status, x.orderAmount, x.orderCount);
                    }
                    Console.WriteLine();
                }

                //Keep the console window open.
                Console.Read();
            }
        }

        /// <summary>
        /// Used to store customer information for analysis.
        /// </summary>
        public class Customer
        {
            //Properties.
            public string Name { get; set; }
            public string City { get; set; }
            public string State { get; set; }

            /// <summary>
            /// Helper method for creating a list of customers
            /// from an Excel worksheet.
            /// </summary>
            public static List<Customer> LoadCustomers(Worksheet worksheet,
              SharedStringTable sharedString)
            {
                //Initialize the customer list.
                List<Customer> result = new List<Customer>();

                //LINQ query to skip first row with column names.
                IEnumerable<Row> dataRows =
                  from row in worksheet.Descendants<Row>()
                  where row.RowIndex > 1
                  select row;

                foreach (Row row in dataRows)
                {
                    //LINQ query to return the row's cell values.
                    //Where clause filters out any cells that do not contain a value.
                    //Select returns the value of a cell unless the cell contains
                    //  a Shared String.
                    //If the cell contains a Shared String, its value will be a
                    //  reference id which will be used to look up the value in the
                    //  Shared String table.
                    IEnumerable<String> textValues =
                      from cell in row.Descendants<Cell>()
                      where cell.CellValue != null
                      select
                        (cell.DataType != null
                          && cell.DataType.HasValue
                          && cell.DataType == CellValues.SharedString
                        ? sharedString.ChildElements[
                          int.Parse(cell.CellValue.InnerText)].InnerText
                        : cell.CellValue.InnerText)
                      ;

                    //Check to verify the row contained data.
                    if (textValues.Count() > 0)
                    {
                        //Create a customer and add it to the list.
                        var textArray = textValues.ToArray();
                        Customer customer = new Customer();
                        customer.Name = textArray[0];
                        customer.City = textArray[1];
                        customer.State = textArray[2];
                        result.Add(customer);
                    }
                    else
                    {
                        //If no cells, then you have reached the end of the table.
                        break;
                    }
                }

                //Return populated list of customers.
                return result;
            }
        }

        /// <summary>
        /// Used to store order information for analysis.
        /// </summary>
        public class Order
        {
            //Properties.
            public string Number { get; set; }
            public DateTime Date { get; set; }
            public string Customer { get; set; }
            public Double Amount { get; set; }
            public string Status { get; set; }

            /// <summary>
            /// Helper method for creating a list of orders
            /// from an Excel worksheet.
            /// </summary>
            public static List<Order> LoadOrders(Worksheet worksheet,
              SharedStringTable sharedString)
            {
                //Initialize order list.
                List<Order> result = new List<Order>();

                //LINQ query to skip first row with column names.
                IEnumerable<Row> dataRows =
                  from row in worksheet.Descendants<Row>()
                  where row.RowIndex > 1
                  select row;

                foreach (Row row in dataRows)
                {
                    //LINQ query to return the row's cell values.
                    //Where clause filters out any cells that do not contain a value.
                    //Select returns cell's value unless the cell contains
                    //  a shared string.
                    //If the cell contains a shared string its value will be a
                    //  reference id which will be used to look up the value in the
                    //  shared string table.
                    IEnumerable<String> textValues =
                      from cell in row.Descendants<Cell>()
                      where cell.CellValue != null
                      select
                        (cell.DataType != null
                          && cell.DataType.HasValue
                          && cell.DataType == CellValues.SharedString
                        ? sharedString.ChildElements[
                          int.Parse(cell.CellValue.InnerText)].InnerText
                        : cell.CellValue.InnerText)
                      ;

                    //Check to verify the row contains data.
                    if (textValues.Count() > 0)
                    {
                        //Create an Order and add it to the list.
                        var textArray = textValues.ToArray();
                        Order order = new Order();
                        order.Number = textArray[0];
                        order.Date = new DateTime(1900, 1, 1).AddDays(
                          Double.Parse(textArray[1]) - 2);
                        order.Customer = textArray[2];
                        order.Amount = Double.Parse(textArray[3]);
                        order.Status = textArray[4];
                        result.Add(order);
                    }
                    else
                    {
                        //If no cells, then you have reached the end of the table.
                        break;
                    }
                }

                //Return populated list of orders.
                return result;
            }
        }

    }
}

[/code]