Stan Stan - 2 months ago 23
C# Question

C# Model - Separation of concerns?

I have a model

Administrator
that has its properties, but it also consists of numerous static methods that do not really tied any way to the current object itself like for example
GetByCredentials(string username, string password);
. Is it somehow possible to divide static methods someplace else and lave object as pure as possible?

Example



public class Administrator : Entity
{
// OBJECT START
public int Id { get; set; }
public DateTime CreatedDateTime { get; set; }
public DateTime UpdatedDateTime { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string PasswordSalt { get; set; }

public void SetNewPassword(string password)
{
var cryptoService = new PBKDF2();
this.Password = cryptoService.Compute(password);
this.PasswordSalt = cryptoService.Salt;
}

public override void OnBeforeInsert()
{
this.CreatedDateTime = DateTime.Now;
this.UpdatedDateTime = DateTime.Now;

this.SetNewPassword(this.Password);
}

public override void OnBeforeUpdate()
{
this.UpdatedDateTime = DateTime.Now;
}
// OBJECT END

// Now I have multiple static methods that do not really
// have anything to do with current object
public static Administrator GetByCredentials(string username, string password)
{
var db = new MainDataContext();
var admin = db.Administrators.SingleOrDefault(x => x.Username == username);
if (admin == null) return null;

ICryptoService cryptoService = new PBKDF2();
var hash = cryptoService.Compute(password, admin.PasswordSalt);

if (hash == admin.Password) return admin;
return null;
}

public static bool IsCurrentIpBanned
{
get
{
const int minutesBlocked = 5;
const int maxLoginCount = 5;

var db = new MainDataContext();
var loginCount = db.AdministratorAuthorizationLogs.AsEnumerable().Count(x => x.Ip == HttpContext.Current.Request.UserHostAddress && x.CreatedDateTime.AddMinutes(minutesBlocked) > DateTime.Now && x.IsSuccess == false);

return loginCount > maxLoginCount;
}
}

public static void LogSuccess(Administrator admin)
{
Administrator.Log(admin, true);
}

public static void LogFailure(Administrator admin)
{
Administrator.Log(admin, false);
}

private static void Log(Administrator admin, bool success)
{
var db = new MainDataContext();
db.AdministratorAuthorizationLogs.Add(new AdministratorAuthorizationLog
{
Username = admin.Username,
Password = admin.Password,
Ip = HttpContext.Current.Request.UserHostAddress,
IsSuccess = success
});

db.SaveChanges();
}
}

Answer

There are several options here, but the main thing is that C# classes are the tool for separating concerns.

The most obvious is to capture those things in their own abstraction(s). For example, the GetByCredentials might be better as a (non-static) member of a different class Authority or similar. That class only needs to be able to create an Administrator type.

You can also use extension methods. A possible candidate for that is Log, which takes an Administrator as an argument and uses only public facilities on it. Extension methods are defined in a separate class, but allow you to use them "as if" they were members of the extended class, e.g.:

public static class AdministratorExtensions
{
    public static void log( this Administrator admin, bool success ) { ... }
}

var admin = new Administrator();
admin.Log( true );

The key thing is to identify real abstractions and build your system up from them by combining them in sensible ways. Separating out concerns is part of that process.

Comments