ASP.NET MVC 静态变量有多安全?

14

我希望确保我的网站将来能够在云端进行托管,并且能够处理大量的请求。

静态变量有多安全?

它们不安全是因为分开的用户请求实际上共享这些静态变量吗?还是因为如果您将站点分布在线程/分片等方式上(以处理高负载),则线程共享静态变量?

主要是我有一些帮助类,其中包含静态属性,我应该更改此架构,以便我创建每个类的实例并访问这些实例吗?

例如,这里是我正在做的示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Mvc.Mailer;

namespace MVCWebsite.Helpers
{
        public class AppSettings
        {
                public static void OnAppInit()
                {
                        //General
                        AppName = "MyApp";
                        DesktopBaseURLs = new Dictionary<string, string>();
                        DesktopBaseURLs.Add("dev", "localhost:50560");
                        DesktopBaseURLs.Add("test", "www.test.whatever.com");
                        DesktopBaseURLs.Add("live", "www.whatever.com");
                        MobileBaseURLs = new Dictionary<string, string>();
                        MobileBaseURLs.Add("dev", "m.local.whatever.com");
                        MobileBaseURLs.Add("test", "m.test.whatever.com");
                        MobileBaseURLs.Add("live", "m.whatever.com");

                        //Emails
                        EmailHostName = AppName + ".com"; //For the moment atleast
                        NoReplyEmailAddress = "no-reply@" + EmailHostName.ToLower();
                        SupportEmailAddress = "support@" + EmailHostName.ToLower();
                        ErrorEmailAddress = "errors@" + EmailHostName.ToLower();

                        //Resources
                        TempFileURL = "/content/temp/";
                        UserDataURL = "/content/user-content/";
                        ProfilePicturesURL = UserDataURL + "profile-pictures/";

                        var a = GlobalHelper.GetURLAsServerPath(ProfilePicturesURL);
                        var b = a;

                }

                //General
                public static string AppName { get; set; }
                public static Dictionary<string, string> DesktopBaseURLs;
                public static Dictionary<string, string> MobileBaseURLs;

                //Emails
                public static string EmailHostName { get; set; }
                public static string NoReplyEmailAddress { get; set; }
                public static string SupportEmailAddress { get; set; }
                public static string ErrorEmailAddress { get; set; }

                //Resources
                public static string UserDataURL { get; set; }
                public static string TempFileURL { get; set; }
                public static string ProfilePicturesURL { get; set; }

                //Methods
                public static void SetAppURL()
                {

                }
        }
}

同样的规则适用于...静态数据在应用程序域内共享。对于共享配置数据(如您的示例),这可能正是您想要的,但要小心只初始化一次,并且从单个线程开始。 - Tim M.
2个回答

16

您的代码不是线程安全的。您正在在多个请求之间共享静态变量,这些请求可能由多个线程执行。请注意,您正在使用作为底层存储的Dictionary<TKey,TValue>类不是线程安全的类,这意味着如果您尝试从多个线程并发地调用OnAppInit方法,则您的代码可能会崩溃得非常严重。另一方面,如果您仅在Application_Start事件中调用此OnAppInit静态方法一次(该事件保证仅从单个线程运行),则可以相当安全地在那里使用它。

话虽如此,说静态变量和方法通常在应用程序中不是一个好主意并不正确。如果您不知道如何正确使用它们,或者如果您不知道如何同步对它们的访问(如果需要从并发线程完成此操作),则它们就是一个坏主意。编写线程安全的代码是一个非常困难的主题,如果您担心会做错(像编写诸如ASP.NET应用程序之类的多线程应用程序时谁不担心?),只需不要像这样共享状态即可。在ASP.NET应用程序中使用已经成熟的位置来存储状态:

  • 后端(例如可以是关系数据库)
  • 应用程序状态
  • 缓存
  • Http上下文状态
  • 会话状态
  • 客户端cookie

这些位置专门设计用于在ASP.NET应用程序中存储状态(当然,第一个位置可以在任何类型的应用程序中使用)。


你能再解释一下吗?你所说的“如果你尝试从多个线程并发调用OnAppInit方法,你的代码可能会崩溃得非常严重”是什么意思?这个方法到底会出现什么问题? - Dmitry Efimenko
3
这个方法修改了一个本地静态变量,是字典类型。正如我在回答中所说,这种类型不是线程安全的。例如,第一个线程将为字典分配一些值并开始向其中添加值,而另一个线程将仅将其分配给一个新的字典,失去第一个线程可能已经保存的所有值。这段代码不应该从多个线程中调用。 - Darin Dimitrov
再次感谢Darin!那么我要么将创建的实例存储在全局对象中以便轻松访问,要么只在每个类中拥有一个静态的Get()方法来返回唯一的实例。这应该可以解决问题。 :) - williamsandonz
不要考虑任何变量。不要考虑类或变量(无论是静态的还是非静态的)。请以我在答案中列出的存储范围为基础,它们在ASP.NET应用程序中可用。因此,请重复它们:后端、应用程序状态、缓存、Http上下文、会话、客户端Cookie。 - Darin Dimitrov
如果我在应用程序中仅用于读取,使用这个静态变量是否是线程安全的? - Yasser Sinjab
显示剩余2条评论

3
静态变量将在请求之间共享。此外,它们将在应用程序启动时初始化,因此如果AppDomain(即应用程序域)重新启动,则它们的值将被重新初始化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接