Веб-часть и синглтоны SharePoint - PullRequest
1 голос
/ 11 мая 2011

У меня есть проект sharepoint, где мы переопределяем окно поиска и некоторые другие вещи.У нас также есть страница веб-части, которая отвечает на окно поиска.Все эти компоненты должны иметь общую конфигурацию.Я думал о создании синглтона, но я не уверен, как это будет очищено / удалено из памяти / удалено.

Есть идеи?Есть какие-нибудь предупреждения об использовании синглетонов в sharepoint?Кроме того, существует ли подходящий способ для совместного использования экземпляра объекта между всеми этими компонентами?

Редактировать: я думал об очень простом синглтоне.Конфигурация должна содержать не более 5-20 строк и не более десяти целых чисел.Нет сложных объектов:)

Ответы [ 3 ]

4 голосов
/ 11 мая 2011

Если ваш объект просто конфигурируется (загружается один раз и остается доступным только для чтения с этой точки), я не буду беспокоиться о том, что он будет одиночным или о том, будет ли / когда он будет собирать мусор (объект не будет собираться, пока вы его не установитек нулю).

В целом, в серверной среде (например, в SharePoint) перед тем, как сделать его одноэлементным, необходимо убедиться в двух вещах об объекте:

  • технические аспекты (в основном безопасность потоковкак указывает Prisoner ZERO, но также и сколько памяти он использует, если он хранит важные файлы (например, файлы) *
  • аспекты безопасности - чрезвычайно легко просачивать информацию пользователя в одноэлементный объект и использовать ее по ошибке некоторыми другимипользователь.Также возможно кэшировать в синглтоне некоторую информацию, к которой у одного пользователя есть доступ, а затем получать информацию от другого пользователя, который не должен иметь доступа к такой информации.
4 голосов
/ 11 мая 2011

Пока объекты, управляемые вашим одноэлементным классом, являются поточно-ориентированными, проблем не должно быть.

Пример:
У меня есть серия объектных вызовов, которые занимали много времени (7+ секунд). Поэтому я решил попробовать использовать технику длинных опросов в стиле комет для их обработки. Таким образом, я размещаю сервис (как статический одноэлементный) в одном потоке и обрабатываю запросы, используя асинхронный протокол HttpHandler ... и он работает ОТЛИЧНО! И поскольку я использую сервис асинхронно, он очень эффективен, потому что вызывающий поток освобождается немедленно (после завершения обработки сервис завершает обратный вызов).

РЕДАКТИРОВАТЬ:
Но ваша проблема с длительным временем обработки все еще существует, поэтому вам все еще (вероятно) нужно асинхронное решение для начальной выборки. Как это? Почему бы не объединить asych-решение с пользовательским кэшированием?

По различным (доступным) причинам я сохраняю свои appSetting в базе данных и использую для этого кеш-кэш.

ПРИМЕР пользовательского кэша:

public enum ConfigurationSection
{
    AppSettings
}

public static class Utility
{
    #region "Common.Configuration.Configurations"

    private static Cache cache = System.Web.HttpRuntime.Cache;

    public static String GetAppSetting(String key)
    {
        return GetConfigurationValue(ConfigurationSection.AppSettings, key);
    }

    public static String GetConfigurationValue(ConfigurationSection section, String key)
    {
        Configurations config = null;

        if (!cache.TryGetItemFromCache<Configurations>(out config))
        {
            config = new Configurations();
            config.List(SNCLavalin.US.Common.Enumerations.ConfigurationSection.AppSettings);
            cache.AddToCache<Configurations>(config, DateTime.Now.AddMinutes(15));
        }

        var result = (from record in config
                      where record.Key == key
                      select record).FirstOrDefault();

        return (result == null) ? null : result.Value;
    }

    #endregion
}

namespace Common.Configuration
{
    public class Configurations : List<Configuration>
    {
        #region CONSTRUCTORS

        public Configurations() : base()
        {
            initialize();
        }
        public Configurations(int capacity) : base(capacity)
        {
            initialize();
        }
        public Configurations(IEnumerable<Configuration> collection) : base(collection)
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud; // Db-Access layer

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
        }

        /// <summary>
        /// Lists one-to-many records.
        /// </summary>
        public Configurations List(ConfigurationSection section)
        {
            using (DbCommand dbCommand = _crud.Db.GetStoredProcCommand("spa_LIST_SecConfiguration"))
            {
                _crud.Db.AddInParameter(dbCommand, "@Section", DbType.String, section.ToString());

                _crud.List(dbCommand, PopulateFrom);
            }

            return this;
        }

        public void PopulateFrom(DataTable table)
        {
            this.Clear();

            foreach (DataRow row in table.Rows)
            {
                Configuration instance = new Configuration();
                instance.PopulateFrom(row);
                this.Add(instance);
            }
        }

        #endregion
    }

    public class Configuration
    {
        #region CONSTRUCTORS

        public Configuration()
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud;

        public string Section { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
            Clear();
        }

        public void Clear()
        {
            this.Section = "";
            this.Key = "";
            this.Value = "";
        }
        public void PopulateFrom(DataRow row)
        {
            Clear();

            this.Section = row["Section"].ToString();
            this.Key = row["Key"].ToString();
            this.Value = row["Value"].ToString();
        }

        #endregion
    }
}
1 голос
/ 11 мая 2011

Я думаю, что вы, возможно, слишком усложняете это и попадаете в ловушку преждевременной оптимизации.

Вы указываете, что ваш объект не имеет ничего больше, чем пара дюжин строк / целых чисел, так что, вероятно, вы не выполняете никаких дорогостоящих настроек, и, следовательно, есть ли что-нибудь, что можно получить с помощью одноэлементного подхода?

Кроме того, реальный вопрос здесь заключается в том, где эти строки / целые числа будут храниться - если он жестко закодирован в вашем классе, вы не сможете легко его обновить, поэтому было бы лучше хранить эту конфигурацию где-то еще.

Шесть способов сохранить настройки в SharePoint

Но IHMO лучший способ сделать это, следуя MSDN SharePoint Guidance Library , которая использует хранилище Property Bag для своей реализации иерархического Configuration Manager, который позволяет вам делать такие вещи, как настройка всей фермы, но переопределяется для определенных семейств сайтов / сайтов и т. д.

Итак, в заключение я лично

  • Реализовать объект конфигурации как простой объект, считывающий значения из менеджера конфигурации
  • Montor / профиль и при необходимости изменить на одиночный
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...