Question

Scenario:

I am maintaining a large ASP.NET application in which all of the methods return a generic list. The main problem this is causing is that the ObjectDataSource does not support methods that return generic lists.

What I am trying to do:

Come up with a way of using an ObjectDataSource without re-writing the existing methods. I have included a technique that works but would like to know if there is a better approach.

I understand any approach to what I am trying will have a negative impact on performance. My main concern is reducing the amount of time I have to spend on maintaining and enhancing this application. However, I would like to implement an approach that has the least impact on performance.

Example of method that returns generic list

    public static List<Widget> GetAll()
    {
        List<Widget> temp = new List<Widget>();

        Widget w1 = new Widget();
        w1.Name = "test 1";
        Widget w2 = new Widget();
        w2.Name = "test 2";

        temp.Add(w1);
        temp.Add(w2);

        return temp;
    }

The following works but I am not sure it is the best approach as it requires iterating the list items

public class Widgets : List<Widget>
{
    public Widgets()
    {}
}


public static Widgets GetAll2()
{
   List<Widget> temp = WidgetManager.GetAll();
   Widgets widgets = new Widgets();
   foreach (Widget widget in temp)
   {
      widgets.Add(widget);
   }
   return widgets;
}

The following does not work.

public class Widgets : List<Widget>
{
    public Widgets()
    {}
}

public static Widgets GetAll2()
{
   List<Widget> tempWidgets1 = GetAll();
   Widgets tempWidgets2 = (Widgets)tempWidgets1;
   return tempWidgets2;
}

The following is the full solution based on the answer & comment provided by KMP & korhner Some of the code above is repeated but with more details.

The key to making this work was to add the following constructor to the Entity List Class. No additional code was required to implement IEnumerable other than adding the constructor.

public Widgets(IEnumerable collection) : base(collection) { }

Data Access Layer

Note that the data access layer returns a List which will not work with ObjectDataSource.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DemoClassLibrary.Entities;

namespace DemoClassLibrary.DAL
{
    public class WidgetDAL
    {
        public static List<Widget> GetAll()
        {
            List<Widget> temp = new List<Widget>();

            Widget w1 = new Widget();
            w1.Name = "test 1";
            Widget w2 = new Widget();
            w2.Name = "test 2";

            temp.Add(w1);
            temp.Add(w2);

            return temp;
        }
    }
}

Entity

No changes need to be made to the entity class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DemoClassLibrary.Entities
{
    public class Widget
    {
        public string Name
        {
            get;
            set;
        }
    }
}

Entity List Class

An Entity List Class needed to be created in order to use the ObjectDataSource. A key requirement I had was that the original DAL could not be modified. Yet the DAL still needed to be used to populate the Entity List Class. The key to making this work was to add the following constructor.

public Widgets(IEnumerable collection) : base(collection) { }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DemoClassLibrary.Entities.Collections
{
    public class Widgets : List<Widget>
    {
        public Widgets(IEnumerable<Widget> collection) : base(collection) { }

        public Widgets()
        { }
    }
}

Business Logic Layer

They key to making the business logic layer work is to instantiate the Widgets class. This effective converts List<Widget> to Widgets.

Widgets tempWidgets2 = new Widgets(tempWidgets1)

using System.ComponentModel;
using DemoClassLibrary.DAL;
using DemoClassLibrary.Entities;
using DemoClassLibrary.Entities.Collections;

namespace DemoClassLibrary.BLL
{
    [DataObjectAttribute()]
    public class WidgetManager
    {
        public static Widgets GetAll()
        {
            List<Widget> tempWidgets1 = WidgetDAL.GetAll();
            Widgets tempWidgets2 = new Widgets(tempWidgets1);
            return tempWidgets2;
        }
    }
}

ASPX Page

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"    Inherits="DemoWebApplication._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
        DataSourceID="ObjectDataSource1">
            <Columns>
                <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
            </Columns>
        </asp:GridView>
        <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
        OldValuesParameterFormatString="original_{0}" SelectMethod="GetAll" 
        TypeName="DemoClassLibrary.BLL.WidgetManager"></asp:ObjectDataSource>
    </div>
    </form>
</body>
</html>
Was it helpful?

Solution

You can implement a constructor in your Widgets class that takes a parameter:

public Widgets(IEnumerable<Widget> collection) : base(collection) { }

Than you can just instantiate it this way:

List<Widget> tempWidgets1 = GetAll();
Widgets tempWidgets2 = new Widgets(tempWidgets1);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top