0

我有 2 节课:

public class CustomerViewModel {
  public SystemViewModel system { get;set; }
}

public class SystemViewModel {
  public bool isReadOnly { get; set; }
}

在方法控制器操作上,我有一个自定义过滤器属性,它执行一些代码并确定用户是否具有只读或写入访问权限。此属性可以应用于跨多个控制器的多个操作。

到目前为止,使用反射我可以使用以下方法访问模型:

var viewModel = filterContext.Controller.ViewData.Model;

我无法将此模型转换为 CustomerViewModel,因为在不同的操作中它可能类似于 SalaryViewModel。我所知道的是,任何需要 readonly 属性的模型都将具有 SystemViewModel 属性。

从我的自定义过滤器中,我需要一种能够更改只读值的方法。

到目前为止,我有这个:

public override void OnActionExecuted(ActionExecutedContext filterContext) {
    var viewModel = filterContext.Controller.ViewData.Model;

    var systemViewModelPropertyInfo = model.GetType()
        .GetProperties()
        .FirstOrDefault(p => p.PropertyType == typeof(SystemViewModel));

    if (systemViewModelPropertyInfo != null) {
        // Up to here, everything works, systemViewModelPropertyInfo is of
        // type PropertyInfo, and the systemViewModelPropertyInfo.PropertyType 
        // shows the SystemViewModel type
        // If we get here, the model has the system property
        // Here I need to try and set the IsReadOnly property to true/false;
        // This is where I need help please
    }
}

已解决 感谢所有参与解决此问题的人。特别感谢Julián Urbano提供了我一直在寻找的解决方案。这是我的过滤器中生成的代码:

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    try
    {
        var viewModel = filterContext.Controller.ViewData.Model;
        var systemViewModelPropertyInfoCount = viewModel.GetType().GetProperties().Count(p => p.PropertyType == typeof(SystemViewModel));

        if(systemViewModelPropertyInfoCount == 1)
        {
            var systemViewModelPropertyInfo = viewModel.GetType().GetProperties().First(p => p.PropertyType == typeof(SystemViewModel));
            if(systemViewModelPropertyInfo != null)
            {
                var systemViewModel = systemViewModelPropertyInfo.GetValue(viewModel, null) as SystemViewModel;

                if(systemViewModel != null)
                {
                    var admin = GetAdmin(filterContext.HttpContext.User.Identity.Name);
                    if(admin != null && _adminService.HasPermission(admin, _privilege, Access.Level.ReadWrite))
                        systemViewModel.ReadOnly = false;
                    else
                        systemViewModel.ReadOnly = true;
                }
            }
        } else if(systemViewModelPropertyInfoCount > 1)
        {
            throw new Exception("Only once instance of type SystemViewModel allowed");
        }
    }
    catch (Exception exception)
    {
        Log.Error(MethodBase.GetCurrentMethod(), exception);
        filterContext.Controller.TempData["ErrorMessage"] = string.Format("Technical error occurred");
        filterContext.Result = new RedirectResult("/Error/Index");
    }
    finally
    {
        base.OnActionExecuted(filterContext);
    }
}
4

2 回答 2

3

我无法将此模型转换为 CustomerViewModel,因为在不同的操作中它可能类似于 SalaryViewModel。我所知道的是,任何需要 readonly 属性的模型都将具有 SystemViewModel 属性。

选项1

在我看来,最好的选择是编写如下界面:

public interface IWithSystemViewModel {
    SystemViewModel System {get;}
}

并从您的类中实现它,就像:

public class CustomerViewModel : IWithSystemViewModel{
    public SystemViewModel System { get;set; }
}
public class SalaryViewModel : IWithSystemViewModel{
    public SystemViewModel System { get;set; }
}

因此您可以对其进行转换并访问该isReadOnly属性:

IWithSystemViewModel viewModel = filterContext.Controller.ViewData.Model as IWithSystemViewModel;
if(viewModel!=null){
    viewModel.System.isReadOnly ...
}

选项 2

如果你想坚持使用反射:

var viewModel = filterContext.Controller.ViewData.Model;
SystemViewModel  theSystem = viewModel.GetType().GetProperty("system")
    .GetValue(viewModel, null) as SystemViewModel;
theSystem.isReadOnly ...

棘手的事情:在您的代码中,您选择类型为SystemViewModel. 但是如果对象实际上有几个SystemViewModel你不知道的属性呢?你确定你访问的是正确的吗?您可以强制它们都使用相同的名称,但话又说回来,这就像使用上面选项 1 中的接口一样。

我肯定会选择选项1。

于 2013-04-11T12:42:58.300 回答
1
var viewModel = new CustomerViewModel();

var systemViewModelPropertyInfo = viewModel.GetType()
    .GetProperties()
    .FirstOrDefault(p => p.PropertyType == typeof(SystemViewModel));

if (systemViewModelPropertyInfo != null) {
    var systemViewModelProperty = systemViewModelPropertyInfo.GetValue(viewModel, null) as SystemViewModel;

    // get the desired value of isReadOnly here...
    var isReadOnly = false;

    // here, systemViewModelProperty may be null if it has not been set.
    // You can decide what to do in that case. If you need a value to be
    // present, you'll have to do something like this...
    if (systemViewModelProperty == null) {
        systemViewModelPropertyInfo.SetValue(viewModel, new SystemViewModel { isReadOnly = isReadOnly }, null);
    }
    else {
        systemViewModelProperty.isReadOnly = isReadOnly;
    }
}

也就是说,如果你实现了一个接口,整个过程可能会更容易......

public interface IHaveSystemViewModel {
    SystemViewModel system { get; set; }
}

var model = viewModel as IHaveSystemViewModel;
if (model != null) {

    // again, you need to make sure you actually have a reference here...
    var system = model.system ?? (model.system = new SystemViewModel());
    system.isReadOnly = false; // or true
}
于 2013-04-11T12:52:23.387 回答