0

프로젝트에서 asp.net mvc 4 및 엔터티 프레임 워크 5를 사용하고 있습니다. 사용자의StackOverflowException 처리되지 않았습니다 : 'System.StackOverflowException'형식의 처리되지 않은 예외가 mscorlib.dll에서 발생했습니다

public class Account : BaseEntity 
{ 
    public string UserName { get; set; } 
    public string Password { get; set; } 
    public byte[] AvatarBinary { get; set; } 
    public string AvatarMimeType { get; set; } 

    public virtual IList<AccountInRole> AccountRoles { get; set; } 
} 

역할 :

public class Role : BaseEntity 
{ 
    public string RoleName { get; set; } 

    public virtual IList<AccountInRole> AccountRoles { get; set; } 
} 

public abstract class BaseEntity 
{   
    [Required] 
    public virtual int Id { get; set; } 

    [Required] 
    public virtual DateTime CreatedOn { set; get; } 

    public virtual string CreatedBy { set; get; } 

    [Required] 
    public virtual DateTime ModifiedOn { set; get; } 

    public virtual string ModifiedBy { set; get; } 
} 

먼저 계정 엔티티 응용 프로그램 사용자를위한 클래스입니다 : 내가 모든 엔티티가 그것에서 파생 된 기본 엔티티가 사용자는 여러 역할을 가질 수 있으며 그 반대의 경우도 가능합니다.

public class AccountInRole : BaseEntity 
{ 
    public int AccountId { get; set; } 
    public int RoleId { get; set; } 

    public virtual Account Account { get; set; } 
    public virtual Role Role { get; set; } 
} 

특정 사용자에 대한 역할을 지정하려면 Accountrepository에서 GetRoles 메서드를 호출하십시오. 이 방법으로이 구현됩니다 :

public class AccountRepository : IAccountRepository 
{ 
#region Properties 
private CharityContext DataContext { get; set; } 

public IQueryable<Account> Accounts 
{ 
    get { return DataContext.Accounts; } 
} 

#endregion 

#region Ctors 

public AccountRepository() : this(new CharityContext()) 
{ 
} 

public AccountRepository(CharityContext db) 
{ 
    DataContext = db; 
} 

#endregion 

#region Methods 

public List<Role> GetRoles(string userName) 
{ 
    var acc = DataContext.Accounts; 

    var query = from u in DataContext.Accounts 
       from r in DataContext.Roles 
       from ur in DataContext.AccountInRoles 
       where ur.AccountId == u.Id && ur.RoleId == r.Id && u.UserName == userName 
       select r; 
    return query.ToList(); 
} 

#endregion 

} 

이 메서드는 컴파일러에서 위의 LINQ 쿼리를 실행하려면 예외가 throw됩니다. 이 예외는 다음과 같습니다

있는 StackOverflowException이 'System.StackOverflowException'형식의 처리되지 않은 예외가 mscorlib.dll에서 발생

처리되지 않은했다

{현재의 thread가에 있기 때문에 식을 계산할 수 없습니다 스택 오버플로 상태}.

GetRoles 메서드는 두 번 호출합니다.

맞춤 권한 부여 속성 0

한번에 :

public class CustomAuthorize : AuthorizeAttribute 
{ 
    //private readonly IAccountRepository _accountRepository; 
    private string[] roles; 

    //public CustomAuthorize(params string[] roles) 
    //{ 
    // this.roles = roles; 
    //} 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     if (httpContext == null) 
      throw new ArgumentNullException("httpContext"); 

     if (!httpContext.User.Identity.IsAuthenticated) 
      return false; 

     if (Roles == string.Empty) 
      return true; 

     var lstRoles = Roles.Split(','); 
     AccountRepository _accountRepository = new AccountRepository(); 
     var userRoles = _accountRepository.GetRoles(httpContext.User.Identity.Name); 
     foreach (var role in lstRoles) 
     { 
      bool isFound = false; 
      foreach (var userRole in userRoles) 
      { 
       if (userRole.RoleName == role) 
        isFound = true; 
      } 
      if (!isFound) return false; 
     } 

     return true; 
    }   
} 

및 Global.asax.cs으로하여 Application_AuthenticateRequest 방법에서 두번째 :

ou는
protected void Application_AuthenticateRequest(Object sender, EventArgs e) 
{ 
    string cookie = FormsAuthentication.FormsCookieName; 
    HttpCookie httpCookie = Request.Cookies[cookie]; 
    if (httpCookie == null) return; 
    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(httpCookie.Value); 
    if(ticket == null || ticket.Expired) return; 
    FormsIdentity identity = new FormsIdentity(ticket); 
    var _accountRepository = new AccountRepository(); 
    var roles = _accountRepository.GetRoles(identity.Name); 
    var principal = new CharityAccount(identity.Name, roles.Select(x => x.RoleName).ToArray()); 
    Context.User = Thread.CurrentPrincipal = principal; 
} 

CharityAccount 상기 방법에서 볼 수있다 이 방법으로 구현 :

public class CharityAccount : IPrincipal 
{ 
    private string[] roles; 
    private IIdentity identity; 

    public IIdentity Identity 
    { 
     get { return identity; } 
    } 

    public bool IsInRole(string role) 
    { 
     return Array.IndexOf(roles, role) >= 0; 
    } 

    public CharityAccount(String name, String[] roles) 
    { 
     identity = new GenericIdentity(name, "Custom authentication"); 
     this.roles = roles; 
    } 
} 

당신의 아이디어에 따르면, 무엇이 문제입니까? 안부

+0

왜 부정 등급입니까? 나는 이해하지 못한다. –

+0

나는 downvote가 많은 양의 정보를 갖고 있다고 상상할 것이다. 문제가 발생한 곳을 좁히지 않았다.과도한 재귀 때문에 stackoverlow가 발생했을 가능성이 있습니다. 순환 참조를 설정하지 않았는지 확인하기 위해 엔티티 외래 키를 확인하는 것이 좋습니다. – Paddy

+0

순환 참조가 있는지 확인합니다. 순환 참조가 없습니다. 이 코드는 정상적으로 작동하지만 로깅 목적으로 ef 코드를 사용하여 두 번째 ** 별도 ** 데이터베이스를 추가 할 때이 오류가 발생했습니다. –

답변

1

당신은 문제를 일으킬 수있는 몇 가지 일을했습니다. 내가 볼 수있는 것은 AccountinRoles에서의 Accounts 역할과 그 반대의 순환 참조입니다.

비록 내가 최고의 디자인이 아니지만 나는 코드를 단순화했다. (하지만 나는 간단하고 어리석은 것을 유지한다고 믿는다.) 엔티티에서 가상 속성이 무엇인지 실제로 의미하는 경우 가상 속성을 유지할 수 있습니다.

이것은 정상적으로 작동합니다.

public abstract class BaseEntity 
{ 
    public int Id { get; set; } 
    public DateTime CreatedOn { set; get; } 
} 

public class Account : BaseEntity 
{ 
    public string UserName { get; set; } 
    public string Password { get; set; } 
} 

public class Role : BaseEntity 
{ 
    public string RoleName { get; set; } 
} 

public class AccountInRole 
{ 
    public int AccountId { get; set; } 
    public int RoleId { get; set; } 
} 

public class Operation 
{ 
    public List<Role> GetRoles() 
    { 
     List<Account> lstAccount = new List<Account>(); 
     List<Role> lstRole = new List<Role>(); 
     List<AccountInRole> lstAccountInRoles = new List<AccountInRole>(); 

     Account ac1 = new Account 
      { 
       Id = 1, 
       UserName = "Jack", 
       Password = "somePassword2", 
       CreatedOn = DateTime.Now 
      }; 
     Account ac2 = new Account 
     { 
      Id = 2, 
      UserName = "Sam", 
      Password = "somePassword1", 
      CreatedOn = DateTime.Now 
     }; 
     lstAccount.Add(ac1); 
     lstAccount.Add(ac2); 

     Role r1 = new Role 
      { 
       Id = 1, 
       RoleName = "TestRole1", 
       CreatedOn = DateTime.Now 
      }; 
     Role r2 = new Role 
     { 
      Id = 2, 
      RoleName = "TestRole2", 
      CreatedOn = DateTime.Now 
     }; 
     lstRole.Add(r1); 
     lstRole.Add(r2); 

     AccountInRole acRole1 = new AccountInRole 
      { 
       AccountId = ac1.Id, 
       RoleId = r1.Id 
      }; 

     AccountInRole acRole2 = new AccountInRole 
     { 
      AccountId = ac2.Id, 
      RoleId = r2.Id 
     }; 
     lstAccountInRoles.Add(acRole1); 
     lstAccountInRoles.Add(acRole2); 

     string userName = "Sam"; 

     // Query the data 
     var roles = from u in lstAccount 
        where u.UserName == userName 
        from acc in lstAccountInRoles 
        from r in lstRole 
        where acc.AccountId == u.Id 
        && r.Id == acc.RoleId 
        select r; 

     return roles.ToList(); 
    } 
} 
+0

감사 합니다만, 계정과 역할 엔티티 사이의 관계는 여러 가지로 많습니다. 변경해서는 안됩니다. 나는 백업에서 프로젝트를 복구하고 지금은 잘 작동합니다. 그러나 나는이 오류의 원인을 정확히 모릅니다. –

관련 문제