Это - дополнительный метод для ASP.NET вспомогательный метод ссылки действия MVC, который позволяет, это для использования контроллера разрешает атрибуты решать, должна ли ссылка быть включена, отключена или скрыта от представления текущего пользователя. Я сохраняю Вас от необходимости включить Ваши ограниченные действия в то, "если" пункты, которые проверяют на пользовательское членство во всех представлениях. Благодаря Maarten Balliauw для идеи и битов кода, которые показали мне путь:)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;
using System.Web.Routing;
using System.Web.Mvc;
using System.Collections;
using System.Reflection;
namespace System.Web.Mvc.Html
{
public static class HtmlHelperExtensions
{
///
/// Shows or hides an action link based on the user's membership status
/// and the controller's authorize attributes
///
/// The link text.
/// The controller action name.
/// The controller name.
///
public static string SecurityTrimmedActionLink(
this HtmlHelper htmlHelper,
string linkText,
string action,
string controller)
{
return SecurityTrimmedActionLink(htmlHelper, linkText, action, controller, false, null);
}
///
/// Enables, disables or hides an action link based on the user's membership status
/// and the controller's authorize attributes
///
/// The link text.
/// The action name.
/// The controller name.
/// if set to true [show link as disabled -
/// using a span tag instead of an anchor tag ].
/// Use this to add attributes to the disabled
/// span tag.
///
public static string SecurityTrimmedActionLink(
this HtmlHelper htmlHelper,
string linkText,
string action,
string controller,
bool showDisabled,
string disabledAttributeText)
{
if (IsAccessibleToUser(action, controller, HttpContext.Current ))
{
return htmlHelper.ActionLink(linkText, action, controller);
}
else
{
return showDisabled ?
String.Format(
"{0}",
linkText,
disabledAttributeText==null?"":" "+disabledAttributeText
) : "";
}
}
private static IController GetControllerInstance(string controllerName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
Type controllerType = GetControllerType(controllerName);
return (IController)Activator.CreateInstance(controllerType);
}
private static ArrayList GetControllerAttributes(string controllerName, HttpContext context)
{
if (context.Cache[controllerName + "_ControllerAttributes"] == null)
{
var controller = GetControllerInstance(controllerName);
context.Cache.Add(
controllerName + "_ControllerAttributes",
new ArrayList(controller.GetType().GetCustomAttributes(typeof(AuthorizeAttribute), true)),
null,
Caching.Cache.NoAbsoluteExpiration,
Caching.Cache.NoSlidingExpiration,
Caching.CacheItemPriority.Default,
null);
}
return (ArrayList)context.Cache[controllerName + "_ControllerAttributes"];
}
private static ArrayList GetMethodAttributes(string controllerName, string actionName, HttpContext context)
{
if (context.Cache[controllerName + "_" + actionName + "_ActionAttributes"] == null)
{
ArrayList actionAttrs = new ArrayList();
var controller = GetControllerInstance(controllerName);
MethodInfo[] methods = controller.GetType().GetMethods();
foreach (MethodInfo method in methods)
{
object[] attributes = method.GetCustomAttributes(typeof(ActionNameAttribute), true);
if ((attributes.Length == 0 && method.Name == actionName)
||
(attributes.Length > 0 && ((ActionNameAttribute)attributes[0]).Name == actionName))
{
actionAttrs.AddRange(method.GetCustomAttributes(typeof(AuthorizeAttribute), true));
}
}
context.Cache.Add(
controllerName + "_" + actionName + "_ActionAttributes",
actionAttrs,
null,
Caching.Cache.NoAbsoluteExpiration,
Caching.Cache.NoSlidingExpiration,
Caching.CacheItemPriority.Default,
null);
}
return (ArrayList)context.Cache[controllerName + "_" + actionName+ "_ActionAttributes"];
}
public static bool IsAccessibleToUser(string actionToAuthorize, string controllerToAuthorize, HttpContext context)
{
IPrincipal principal = context.User;
//cache the attribute list for both controller class and it's methods
ArrayList controllerAttributes = GetControllerAttributes(controllerToAuthorize, context);
ArrayList actionAttributes = GetMethodAttributes(controllerToAuthorize, actionToAuthorize, context);
if (controllerAttributes.Count == 0 && actionAttributes.Count == 0)
return true;
string roles = "";
string users = "";
if (controllerAttributes.Count > 0)
{
AuthorizeAttribute attribute = controllerAttributes[0] as AuthorizeAttribute;
roles += attribute.Roles;
users += attribute.Users;
}
if (actionAttributes.Count > 0)
{
AuthorizeAttribute attribute = actionAttributes[0] as AuthorizeAttribute;
roles += attribute.Roles;
users += attribute.Users;
}
if (string.IsNullOrEmpty(roles) && string.IsNullOrEmpty(users) && principal.Identity.IsAuthenticated)
return true;
string[] roleArray = roles.Split(',');
string[] usersArray = users.Split(',');
foreach (string role in roleArray)
{
if (role == "*" || principal.IsInRole(role))
return true;
}
foreach (string user in usersArray)
{
if (user == "*" && (principal.Identity.Name == user))
return true;
}
return false;
}
private static Type GetControllerType(string controllerName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes())
{
if (
type.BaseType!=null
&& type.BaseType.Name == "Controller"
&& (type.Name.ToUpper() == (controllerName.ToUpper() + "Controller".ToUpper())))
{
return type;
}
}
return null;
}
}
}
Это лучший подход, чем пытаться установить ThreadState. Если вы посмотрите документацию для ThreadState , там конкретно сказано, что StopRequested предназначен только для внутреннего использования.
Установка логического значения из другого потока - безопасная операция. В этом случае блокировка не требуется.
Вы можете использовать BackgroundWorker , чтобы сделать эту работу за вас, используя RunWorkerAsync ()
и обрабатывая работника . CancellationPending == true
в вашей логике.
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += MyWorkFunction;
worker.RunWorkerCompleted += MyWorkDoneSuccessfullyFunction;
worker.RunWorkerAsync();
Другим решением может быть использование volatile bool, чтобы сигнализировать, что вам нужно остановиться, что вы можете установить где угодно в классе.
private volatile bool cancelWork = false;
public void CancelWork()
{
cancelWork = true;
}
Вероятно, будет лучше использовать объект Event. Особенно, если ваш поток блокируется. (Тогда вы все еще можете дождаться события внутри блокирующего вызова)
Меня беспокоит то, что StopRequested получает значение True на другой поток. Это безопасно?
Убедитесь, что в поле StopRequested
есть ключевое слово volatile . См. этот другой ответ , чтобы узнать причину этого.
Вы можете использовать Thread.Abort () и заключить любую необходимую очистку в метод DoWork () в блок finally.
Если вы используете BackgroundWorker , вы должны вызвать функцию CancelAsync BackgroundWorker, которая устанавливает для свойства CancellationPending значение true, это то, что вы должны искать в своем цикле:
public void Run(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if(worker != null)
{
while (!worker.CancellationPending)
{
DoWork();
}
}
}
Выше будет код события DoWork , который вызывается при запуске функции RunWorkerAsync .