Разумно ли использовать статический метод для проверки безопасности в ASP.net? - PullRequest
1 голос
/ 06 августа 2010

У меня есть статический метод, подобный этому

public static string DoSomethingToString(string UntrustedString)
{
//parse format and change string here.
return newString.
}

Поскольку я знаю, что множественные вызовы:

static int myInt=0;
public static int AddNumber()
{
lock(someObject)
{
myInt++;
return myInt;    
 }
}

будут возвращать постоянно увеличивающееся число (которое распределяется между страницами),Я не уверен, как локальные переменные будут обрабатываться в DoSomethingToString ();

Я хотел бы узнать условия, в которых статический метод может безопасно / небезопасно использоваться в ASP.net просто для того, чтобы поместить мойМногопоточный мозг, чтобы отдохнуть на эту тему.

ОБНОВЛЕНИЕ:

Большая часть обсуждения была вокруг типов значений.Как узнать, когда безопасно вызывать методы (явные или неявные), которые меняют мои ссылочные типы?Достаточно ли просматривать документацию MSDN и использовать только те методы, в которых указано «threadSafe»?

Один из примеров того, что я называю неявным изменением, - это использование String.Split (), поскольку он является частью того же класса.Я думаю, что есть вероятность того, что некоторые характеристики безопасности являются общими и что требуется меньше беспокойства / усердия.(?)

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

Ради обсуждения предположим, что у меня есть метод с такой подписью:

ValidateStringAndContext(string untrustedString, Object myCustomUserContext)

и у него есть статический метод, который ссылается на следующий объект

public SecurityChecker
{
public static object CheckSecurityStatic(string DirtyData)
{
//do string.split
//maybe call a database, see if it's a token replay 
//

//OR  - alternate implementation
SecurityChecker sc = new SecurityChecker();
 if (sc.CheckSecurity(DirtyData))
  {
  myCustomUserContext.Property1 = new GUID()
  }
return myCustomUserContext;
}


public class bool CheckSecurity(string DirtyData)
{
//do string.split
//maybe call a database, see if it's a token replay 
// return true if OK return false if not
}
}

Пересмотренный вопрос

Буду ли я сталкиваться с проблемами параллелизма (переменные перезаписывают друг друга), если статическийСоздаваемый мной класс «утилит» должен был создать экземпляр другого объекта и затем вызвать метод --versus--, просто вызвав статический метод напрямую?

Ответы [ 3 ]

2 голосов
/ 06 августа 2010

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

Как всегда, необходимо учитывать параллелизм, когда несколько потоков обращаются к общему ресурсу. Если ресурс существует только в контексте вызова метода, параллелизм не является проблемой.

Смотри также: /493745/staticheskie-metody-net-i-ego-vliyanie-na-parallelizm

1 голос
/ 06 августа 2010

У меня такое ощущение, что вы думаете, что переменные могут быть только экземплярами или статическими, и забываете, что локальные переменные отличаются от обоих.Рассмотрим:

public class MyClass
{
    public int InstanceInt;
    public static int StaticInt;
    public int InstanceMethod()
    {
        int i = new Random().Next(1, 50);
        return i;
    }
    public static int StaticMethod()
    {
        int j = new Random().Next(1, 50);
        return j;
    }
}

Здесь InstanceInt - это переменная экземпляра, а StaticInt - статическая переменная.Оба из них требуют блокировки, если к ним будут обращаться разные потоки, однако, к InstanceInt будут обращаться разные потоки, только если к экземпляру MyClass будут обращаться разные потоки.Это может произойти с static MyClass AllThreadsSeeMe = new MyClass(), хранением в статической коллекции, явной передачей его другому потоку и т. Д., Но в противном случае этого не произойдет.StaticInt тем временем по своей сути доступен всем потокам, работающим в приложении, даже если вы позаботитесь о том, чтобы ни один экземпляр MyClass не был разделен между потоками.

Между тем, i и jоба являются локальными для своих функций.Каждый поток, вызывающий функцию, получит свою собственную копию i или j, независимо от того, сколько потоков может вызвать их.Следовательно, они по своей природе потокобезопасны.Только если любой из этих методов изменяет статическую переменную или переменную экземпляра или считывает изменяемую статическую переменную или переменную экземпляра, которые могут быть изменены другим методом, они не являются поточно-ориентированными (immutable - readonly - переменные также являются поточно-безопаснымипотому что другой поток не может изменить свое значение, поскольку ни один поток не может его изменить).

1 голос
/ 06 августа 2010

Есть несколько очень важных моментов, имеющих отношение к коду, который не отображается, чем код, показанный в вопросе ...

Метод DoSomeThingToString является статическим, и любые переменные, объявленные в этом методе, будут локальными по отношению к стеку вызовов этого потока. Если используемые переменные определены вне функции, в этой памяти у вас будут состязания. Убедитесь, что это выглядит так, используя только локальные переменные:

public static string DoSomethingToString(string UntrustedString)
{
    var newString = UntrustedString;
    // operations on newString...
    return newString;
}

Метод AddNumber может вызывать другие проблемы, которые могут быть неочевидными. Если это действительно то, что вы пытаетесь сделать, чтобы добавить число, сделайте это так:

System.Threading.Interlocked.Increment(ref myInt);

Метод Interlocked.Increment гарантирует, что операция будет завершена за один такт.

В противном случае использование ключевого слова lock может быть непростым делом в некоторых редких ситуациях. Вот несколько практических правил. Всегда блокируйте объект, который вы одновременно создаете и на который ссылаетесь, и даже лучше, который вы никогда не сможете изменить. Это означает: только чтение и назначение адреса памяти при создании класса. Это выглядит так:

static int myInt=0;
static readonly object aGoodLock = new object();
public static int MoreComplexIntStuff()
{
    lock(aGoodLock)
    {
        // Do stuff with myInt...
    }
    return myInt;
}

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

Лучший способ помочь вашим коллегам-разработчикам (и, возможно, вашей собственной долговременной памяти) с этим - создать переменную и блокировку, которая ее обернет private, и выставить myInt с помощью свойства, где вы будете осторожны использовать замок в get и set.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...