Можем ли мы использовать одну и ту же таблицу данных для метода страницы и веб-метода в ASP.NET?

Я пытаюсь создать новую веб-страницу, на которой мне нужно отобразить почти 10 различных видов сетки и диаграмм.

Gridviews привязываются к событию загрузки страницы, а диаграммы отображаются с использованием метода jquery-ajax (с использованием amcharts, а также highcharts) путем вызова WebMethod.

Первоначально я реализовал страницу таким образом, что после выполнения одного и того же набора хранимых процедур для просмотра сетки (для отображения данных представления сетки) и веб-методов (для рисования диаграмм). Таким образом, одни и те же sps выполняются дважды для этой страницы (один для сетки и другой для диаграммы ).Для извлечения данных требуется выполнить 10 операций.

Итак, для повышения производительности страницы я создал статическую таблицу данных, подобную этой.

static DataTable Report1;

и привязал вид сетки следующим образом.

private void gvbindReport1()
    {
        try
        {            
            Report1 = new DataTable();//refreshed datatable 
            DataSet ReportDS1 = objmvbl.GetReportGraph(ClientID, date_From, date_To);
            if (ReportDS1.Tables.Count > 0)
            {
                Report1 = ReportDS1.Tables[0];//bindinding data to static datatable

            }
            GdReport.DataSource = Report1;
            GdReport.DataBind();
        }
        catch (Exception ex)
        {
            Log.Errlog("Error Occured in  gvbindReport1 : " + ex.Message.ToString());
        }

    }

и внутри веб-метода я использовал ту же таблицу данных для рисования диаграммы, подобной этой

 [System.Web.Services.WebMethod]
    public static string GetDataReport1()
    {
        System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
        Dictionary<string, object> row;
        try
        {
            //processing for the data inside static datatable
            if (Report1.Rows.Count > 0)
            {
                foreach (DataRow dr in Report1.Rows)
                {
                    row = new Dictionary<string, object>();
                    foreach (DataColumn col in Report1.Columns)
                    {
                        row.Add(col.ColumnName, dr[col]);
                    }
                    rows.Add(row);
                }
            }
        }
        catch (Exception ex)
        {
            Log.Errlog("Error Occured in  GetDataReport WebMethod of Report Page : " + ex.Message.ToString());
        }

        return serializer.Serialize(rows);

    }

с этим я могу показать как сетку, так и диаграммы.

Теперь, пожалуйста, скажите мне, это правильный подход к работе с веб-методами? я читал, что вебметод не имеет никакого отношения к странице и все такое. Подскажите пожалуйста недостатки этого метода.

Если это не так, предложите лучший способ улучшить производительность страницы?


person AcAnanth    schedule 28.09.2015    source источник
comment
Во-первых, вам не следует вручную вызывать JavaScriptSerializer. Если вы просто вернете List<Dictionary<string, object>> напрямую, ASP.NET справится с его сериализацией. Он делает это независимо от вашего типа возвращаемого значения, поэтому ваш текущий код выполняется JavaScriptSerializer дважды для результата (и вам приходится дважды анализировать его на стороне клиента). Дополнительная информация: encosia.com/   -  person Dave Ward    schedule 30.09.2015
comment
@ Дэйв Уорд: спасибо, Дэйв, за указание на это. Можете ли вы сказать, как синхронизировать данные между страницей и веб-методом?   -  person AcAnanth    schedule 01.10.2015
comment
Можете ли вы сделать дамп с помощью DataTables и вместо этого использовать статически типизированные классы и общий список T›?   -  person sm14    schedule 02.10.2015


Ответы (4)


Нет, это не правильный метод. Поскольку вы объявили DataTable как static (статическая переменная имеет область применения и не может быть создана), все

пользователи получат тот же результат (последние обновленные значения).

Вы можете реализовать это при параллельном тестировании.

Пожалуйста, проверьте следующий сценарий:

Учтите, что dtbl — это статический dataTable, который инициализируется на домашней странице, и вы создаете еще один экземпляр `datatable на индексной странице (оба находятся в загрузке страницы, как показано ниже).

Главная

public static DataTable dtbl;
protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        dtbl = new DataTable();
        dtbl.Columns.Add("id");
        dtbl.Columns.Add("name");
        for (int i = 0; i < 10; i++)
        {
            DataRow dr = dtbl.NewRow();
            dr["id"] = i.ToString();
            dr["name"] = i + 1;
            dtbl.Rows.Add(dr);
        }
    }
}

Главная страница

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        home.dtbl = new DataTable();
    }
}

Теперь поставьте точку останова при загрузке каждой страницы и запустите приложение,

  • Откройте обе страницы в separate tab.
  • Обновите домашнюю страницу и проверьте, отображаются ли столбцы
  • Теперь перейдите на следующую вкладку (индекс) и обновите ее (для dt создается новый экземпляр). Это повлияет на таблицу данных, теперь вы также получите новую таблицу данных дома.
  • Таким образом, если эти два процесса/страницы выполняются одновременно, последнее значение будет получено для обеих страниц. Вот почему я говорю, что это будет реализовано в тестировании параллелизма.

В этом случае вы можете использовать сеанс. Рассмотрим следующий код:

Главная

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        dtbl = new DataTable();
        dtbl.Columns.Add("id");
        dtbl.Columns.Add("name");
        for (int i = 0; i < 10; i++)
        {
            DataRow dr = dtbl.NewRow();
            dr["id"] = i.ToString();
            dr["name"] = i + 1;
            dtbl.Rows.Add(dr);
        }
        if (((DataTable)Session["MyDatatable"]).Columns.Count < 0)
        {
            Session["MyDatatable"] = dtbl;
        }
        else
        {
            dtbl = (DataTable)Session["MyDatatable"];
        }
    }
}
person sujith karivelil    schedule 28.09.2015
comment
для отдельных пользователей не создается отдельная таблица данных, все они используют одно и то же, поэтому для всех будет получено последнее обновленное значение. - person sujith karivelil; 28.09.2015
comment
Отчет1 = новая таблица данных(); это не будет работать должным образом? скажем, пользователь 1 получает доступ к сетке страницы и показанному графику. Затем пользователь 2 получает доступ к новой сетке, и график будет отображаться правильно? - person AcAnanth; 28.09.2015
comment
: Спасибо за подробное объяснение. Есть ли другой способ синхронизировать данные между двумя? - person AcAnanth; 01.10.2015
comment
Я считаю, что переменная сеанса здесь является неправильным подходом, поскольку предполагается, что все пользователи ссылаются на одни и те же данные (если я не понял неправильно). Сеанс будет хранить отдельную таблицу данных для каждого подключенного пользователя, что в зависимости от ресурсов сервера + трафика + размера таблицы данных может привести к большой утечке ресурсов. - person HBomb; 06.10.2015
comment
HBomb: у всех пользователей не будет одинаковых данных... идентификатор клиента и диапазон дат изменятся - person AcAnanth; 07.10.2015
comment
Если диапазон дат изменится, тогда сессия является правильной областью действия переменной для использования. Однако имейте в виду мой комментарий о размере ресурса. Если сеанс содержит 10 очень больших наборов данных на пользователя И вы испытываете большой трафик, это может быть довольно большой нагрузкой на ресурсы. - person HBomb; 07.10.2015
comment
Конечно, вы можете использовать одни и те же базовые данные для всех пользователей через объект Cache (см. мой ответ ниже) и выполнять фильтрацию кэшированных результатов на основе даты и возвращать эти отфильтрованные результаты в клиент. Вы можете получить прирост производительности, сохраняя обращение к базе данных при каждом вызове, если у вас достаточно памяти сервера И наборы данных большие. - person HBomb; 08.10.2015
comment
@down-Voter: ценю настроение и спасибо за поддержку. Это открытое сообщество, а не место для личной мести. - person sujith karivelil; 21.06.2016

Во-первых, не используйте, как правило, статические переменные в веб-приложении. Они действуют как глобальные переменные и не создаются при каждом запросе.

Я бы также не советовал вам использовать DataTables вплоть до вашего уровня пользовательского интерфейса. Вместо этого работайте со строго типизированными объектами.

  1. Создайте модель объекта, который вы пытаетесь связать.

Например, если у вас есть таблица с именем person со следующими полями.

Id | first_name | last_name | audit_ts

Вы можете создать объект как таковой:

public class Person
{
    public int Id {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
}
  1. Теперь в отдельных функциях в каком-то классе вы можете вызвать свою хранимую процедуру из базы данных, а затем преобразовать строки таблицы в таблицу person в список объектов Person.

  2. Теперь вместо того, чтобы дважды вызывать хранимую процедуру для получения одних и тех же данных, что только снижает производительность вашего приложения, вы можете вместо привязки представления сетки в коде выполнить событие Page_Load. Просто привяжите таблицу HTML после того, как вы вызовете свой веб-метод, который, как я полагаю, находится в вашем code-behind . Вы можете обратиться к этой публикации о том, как связать таблицу HTML с объектом JSON. возвращается вашим вызовом Ajax.

  3. Таким образом, вы делаете один вызов на сервер и в базу данных, чтобы использовать одни и те же данные для привязки таблицы и диаграмм.

person Nabin Karki Thapa    schedule 02.10.2015

Это хороший вариант использования малоиспользуемого объекта Cache Object. Многие пользователи понимают ViewState и SessionState, однако объект Cache используется не так широко, и хотя его концепция очень похожа, он гораздо более гибкий.

Если ваша страница вызывает 10 хранимых процедур дважды (один раз для ваших сеток и второй раз для ваших диаграмм), давайте повысим производительность примерно на 100 %, исключив дополнительные вызовы с помощью объекта Cache.

Сделайте один вызов хранимых процедур в отдельном методе, который заполняет объект кэша таблиц данных, который затем повторно используется во всем приложении.

private void loadReport1IntoCache()
{
  //...load your data from DB into the Report1 variable here


  //this line is new, and it saves your data into a global Cache variable
  //with an absolute expiration of 10 minutes
  Cache.Insert("Report1", Report1, null,
  DateTime.Now.AddMinutes(10d), 
  System.Web.Caching.Cache.NoSlidingExpiration);


}

Затем, когда вы находитесь внутри других методов, вы можете использовать переменную Cache вместо повторного вызова хранимых процедур. Например:

[System.Web.Services.WebMethod]
public static string GetDataReport1()
{
   //first load the application variable before performing your other work
   DataTable myCachedReport1Data = (DataTable)Cache["Report1"];
   //did the Cache expire?
   if (myCachedReport1Data == null)
   {
   //if so refresh it
   loadReport1IntoCache();
   //and then assign the variable the contents of the refresh and proceed
   myCachedReport1Data = (DataTable)Cache["Report1"];
   }

   //other work here, utilizing the myCachedReport1Data variable
}

и для вашей привязки к сетке:

private void gvbindReport1()
{
    try
    {            
        DataTable myCachedReport1Data = (DataTable)Cache["Report1"];
        //did the Cache expire?
        if (myCachedReport1Data == null)
        {
          //if so refresh it
          loadReport1IntoCache();
          //and then assign the variable the contents of the refresh
          myCachedReport1Data = (DataTable)Cache["Report1"];
        }

        GdReport.DataSource = myCachedReport1Data ;
        GdReport.DataBind();
    }
    catch (Exception ex)
    {
        Log.Errlog("Error Occured in  gvbindReport1 : " +  ex.Message.ToString());
    }

}

Теперь вам нужно будет сделать несколько вещей, не упомянутых здесь. Вам следует подумать, когда вы хотите, чтобы срок действия ваших данных кэша истек (приведенный пример — 10 минут). Также вам следует подумать, хотите ли вы, чтобы это было абсолютное количество минут (абсолютный срок действия) или количество минут с момента последнего доступа (скользящий срок действия). В вашем случае, вероятно, абсолютный срок действия, но это знаете только вы. Затем вы установите срок действия при установке содержимого переменной.

См. документацию по кэшу здесь: https://msdn.microsoft.com/en-us/library/6hbbsfk6.aspx

Добавление данных кэша: https://msdn.microsoft.com/en-us/library/18c1wd61.aspx

Получение данных кэша: https://msdn.microsoft.com/en-us/library/xhy3h9f9.aspx

person HBomb    schedule 06.10.2015

Глядя на приведенный вами пример кода (и параметры date_from и date_to, которые вы передаете в GetReportGraph()), я предполагаю:

  1. у вас есть 2 поля ввода, в которых пользователь указывает диапазон дат, а затем отправляет данные (вызывая обратную передачу), на основе которых вы фильтруете записи и показываете их в сетке и диаграмме.

  2. поскольку разные пользователи будут предоставлять разные диапазоны дат, вы не хотите показывать одни и те же данные всем пользователям.

  3. поскольку данные фильтруются, у них не будет тысяч записей.

Я не уверен, какие функции представления сетки вы используете. Используется ли он только для отображения табличных данных только для чтения? Если да, вы можете рассмотреть подход, предложенный @Nabin Karki Thapa. Если нет, проверьте альтернативный подход ниже:

После того, как вы получили таблицу данных и привязали ее к сетке, немедленно сериализуйте ее в JSON и зарегистрируйте как блок скрипта (определите переменную JS и назначьте сериализованный JSON в качестве ее значения).

На стороне клиента при построении диаграммы вместо вызова веб-метода для получения объекта JSON используйте зарегистрированную вами переменную JS. Таким образом, вы вообще избежите вызова веб-метода (AJAX) и вызова дополнительной хранимой процедуры.

person Vivek Athalye    schedule 07.10.2015