SharePoint Web Part & Singletons

本文关键字:Singletons amp Web Part SharePoint | 更新日期: 2023-09-27 17:56:17

我有一个sharepoint项目,我们可以在其中覆盖搜索框和其他一些东西。我们还有一个响应搜索框的 Web 部件页。所有这些组件都应共享单个配置。我想过创建一个单例,但我不确定如何清理/从内存中删除/卸载。

有什么想法吗?有关在 SharePoint 中使用单一实例的任何警告?另外,有没有一种正确的方法可以在所有这些组件之间共享对象的实例?

编辑:我在想一个非常简单的单例。配置最多只需要包含 5-20 个字符串和十几个整数。没有复杂的对象:)

SharePoint Web Part & Singletons

只要由单一实例类管理的对象是线程安全的,就应该没有问题。

例:
我有一系列需要很长时间才能处理的对象调用(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
    }
}

如果你的对象只是配置(加载一次,然后从那一点开始保持只读),我不会担心它像单例一样,或者它是否/何时会被垃圾回收(除非你将其设置为 null,否则不会收集对象)。

通常,在服务器环境(如 SharePoint)中,在考虑将其设为单一实例之前,您需要确保有关对象的 2 件事:

  • 技术方面(主要是Prisoner ZERO指出的线程安全性,以及它使用多少内存,如果它拥有关键资源,则包含关键文件)
  • 安全方面 - 将用户的信息泄漏到单例对象中并被其他用户错误地使用它是非常容易的。还可以在单例中缓存一个用户有权访问的某些信息,然后由不应访问此类信息的另一个用户检索。
我认为

您可能过于复杂化并陷入过早优化的陷阱。

指出您的对象不超过几十个字符串/整数,因此大概您没有进行任何昂贵的设置,因此使用单例方法实际上可以获得什么吗?

此外,这里真正的问题是这些字符串/整数将存储在哪里 - 如果它硬编码到您的类中,那么您就无法轻松更新它,因此最好将该配置存储在其他地方。

在 SharePoint 中存储设置的六种方法

但 IHMO 执行此操作的最佳方法是遵循 MSDN SharePoint 指南库,该库使用属性包存储来实现分层配置管理器,该管理器允许您执行服务器场范围的设置等操作,但对某些网站集/网站等进行覆盖。

所以总而言之,我个人会

    将配置对象
  • 实现为从配置管理器读取值的简单对象
  • 如有必要,更改为单例/配置文件