condense c# dnn module settings code - c#

This is a code block I use in most of my DNN Settings modules but it seems too verbose for what it does. How would you condense this to make it more usable or at least less redundant?
/// -----------------------------------------------------------------------------
/// <summary>
/// LoadSettings loads the settings from the Database and displays them
/// </summary>
/// -----------------------------------------------------------------------------
public override void LoadSettings()
{
try
{
if (Page.IsPostBack == false)
{
ddlTreeTabId.DataSource = GetTabs();
ddlTreeTabId.DataBind();
if (!string.IsNullOrEmpty((string)TabModuleSettings["TreeTabID"]))
{ //Look for the tree tab id
this.ddlTreeTabId.SelectedValue = (string)TabModuleSettings["TreeTabID"];
//If we're here, we have a tab module id, now we can grab the modules on that page
LoadTabModules(ddlTreeModuleID, int.Parse((string)TabModuleSettings["TreeTabID"]));
//we only do this part if the proceeding steps checked out
//if we have a tree module id
if (!string.IsNullOrEmpty((string)TabModuleSettings["TreeModuleID"]))
{
try
{
//carefully try to select that item from the module id drop down list
this.ddlTreeModuleID.SelectedValue = (string)TabModuleSettings["TreeModuleID"];
}
catch (Exception ex)
{ //There may have been a module id but it aint on that page any more. Ignore the error.
// I hate invoking try just to ignore an error. seems wasteful.
}
}
}
}
catch (Exception exc) //Module failed to load
{
Exceptions.ProcessModuleLoadException(this, exc);
}
}
My ideal solution would implement the properties in such a way that throughout the module a Tree Module ID can be returned without typing all this.
if (!string.IsNullOrEmpty((string)Settings["TreeTabID"]) &&
!string.IsNullOrEmpty((string)Settings["TreeModuleID"]))
{
Do_SomethingWithTheIDs(
int.Parse((string)Settings["TreeTabID"]),
int.Parse((string)Settings["TreeModuleID"]));
}
Imagine the complexity of loading several modules like that. Ugh.
UPDATE
Thanks to Olivier, I've wrote a new class to manage the properties
public class TreeSettingsBase : ModuleSettingsBase
{
public int? TreeTabID
{
get
{
string s = (string)Settings["TreeTabID"];
int id;
return Int32.TryParse(s, out id) ? id : (int?)null;
}
}
public int? TreeModuleID
{
get
{
string s = (string)Settings["TreeModuleID"];
int id;
return Int32.TryParse(s, out id) ? id : (int?)null;
}
}
public int? PersonTabID
{
get
{
string s = (string)Settings["PersonTabID"];
int id;
return Int32.TryParse(s, out id) ? id : (int?)null;
}
}
public int? PersonModuleID
{
get
{
string s = (string)Settings["PersonModuleID"];
int id;
return Int32.TryParse(s, out id) ? id : (int?)null;
}
}
}
So now my LoadSettings looks like this:
public override void LoadSettings()
{
try
{
if (Page.IsPostBack == false)
{
ddlTreeTabId.DataSource = GetTabs();
ddlTreeTabId.DataBind();
if (TreeTabID.HasValue)
{
this.ddlTreeTabId.SelectedValue = TreeTabID.ToString();
LoadTabModules(ddlTreeModuleID, TreeTabID.Value);
if (TreeModuleID.HasValue)
{
try
{
this.ddlTreeModuleID.SelectedValue = TreeModuleID.ToString();
}
catch (Exception ex)
{
}
}
}
ddlPersonTabId.DataSource = GetTabs();
ddlPersonTabId.DataBind();
if (PersonTabID.HasValue)
{
this.ddlPersonTabId.SelectedValue = PersonTabID.ToString();
LoadTabModules(ddlPersonModuleID, PersonTabID.Value);
if (PersonModuleID.HasValue)
{
try
{
this.ddlPersonModuleID.SelectedValue = PersonModuleID.ToString();
}
catch (Exception ex)
{
}
}
}
}
}
catch (Exception exc) //Module failed to load
{
Exceptions.ProcessModuleLoadException(this, exc);
}
}
ModuleSettingsBase is available everywhere so TreeTabID, TreeModuleID, PersonTabID and PersonModuleID will be too. That's what I wanted and it uses less code so thanks Olivier!
It would be nice to ditch the try catch but there's no guarantee the value will be in the drop down list otherwise it would be even smaller. Still better though.

Create a wrapper class for your settings.
public class TabModuleSettingsWrapper {
private SettingsCollection _settings; // I do not know of which type your settings are.
public TabModuleSettingsWrapper(SettingsCollection settings) {
_settings = settings;
}
public int? TreeModuleID {
get {
string s = (string)_settings["TreeModuleID"];
int id;
return Int32.TryParse(s, out id) ? id : (int?)null;
}
}
// Repeat this for all the settings
}
Now you can access the settings with:
var settings = new TabModuleSettingsWrapper(TabModuleSettings);
if (settings.TreeTabID.HasValue && settings.TreeModuleID.HasValue) {
Do_SomethingWithTheIDs(settings.TreeTabID, settings.TreeModuleID);
}

Related

HttpSessionStateBase losing property values of inherited type

We are using HttpSessionStateBase to store messages in a set up similar to this working example:
public class HttpSessionMessageDisplayFetch : IMessageDisplayFetch
{
protected HttpSessionStateBase _session;
private IList<ICoreMessage> messages
{
get
{
if (_session[EchoCoreConstants.MESSAGE_KEY] == null)
_session[EchoCoreConstants.MESSAGE_KEY] = new List<ICoreMessage>();
return _session[EchoCoreConstants.MESSAGE_KEY] as IList<ICoreMessage>;
}
}
public HttpSessionMessageDisplayFetch()
{
if (HttpContext.Current != null)
_session = new HttpSessionStateWrapper(HttpContext.Current.Session);
}
public void AddMessage(ICoreMessage message)
{
if (message != null)
messages.Add(message);
}
public IEnumerable<IResultPresentation> FlushMessagesAsPresentations(IResultFormatter formatter)
{
var mToReturn = messages.Select(m => m.GetPresentation(formatter)).ToList();
messages.Clear();
return mToReturn;
}
}
When we pass in a QualityExplicitlySetMessage (which inherits from ICoreMessage, see below) it is saved correctly to messages.
This is how the object looks after being inserted into the messages list, at the end of AddMessage(ICoreMessage message) above.
But when we come to access it after changing controllers the inherited member's properties are null, which causes a variety of null reference exceptions.
This is how the object now looks after we call FlushMessagesAsPresentations. I've commented out var mToReturn... as this tries to access one of these null ref properties.
I'd like to ask the following:
Why is the HttpSessionStateBase failing to capture these values taken
by the inherited type?
Is this an issue in saving to the HttpSession or in retrieving?
Is this anything to do with, as I suspect, inheritance?
Or is the fact I'm potentially calling a new controller that dependency injects the HttpSessionMessageDisplayFetch causing an issue?
I'm a first-time poster so please let me know if I'm making any kind of faux pas - Super keen to learn! Any input is very welcome.
Some potentially useful code snippets:
QualityExplicitlySetMessage
public class QualityExplicitlySetMessage : QualityChangeMessage
{
public QualityExplicitlySetMessage(IQPossession before, IQPossession after, IQEffect qEffect)
: base(before, after, qEffect)
{
IsSetToExactly = true;
}
}
QualityChangeMessage - Working example
public abstract class QualityChangeMessage : CoreMessage, IQualityChangeMessage
{
protected PossessionChange Change;
public PossessionChange GetPossessionChange()
{
return Change;
}
protected QualityChangeMessage(IQPossession before, IQPossession after, IQEffect qEffect)
{
Change = new PossessionChange(before, after, qEffect);
StoreQualityInfo(qEffect.AssociatedQuality);
}
public override IResultPresentation GetPresentation(IResultFormatter formatter)
{
return formatter.GetQualityResult(this);
}
#region IQualityChangeMessage implementation
public int LevelBefore
{
get { return Change.Before.Level; }
}
//... And so on with values dependent on the Change property.
}
CoreMessage - Working example
public abstract class CoreMessage : ICoreMessage
{
public string MessageType
{
get { return GetType().ToString(); }
}
public string ImageTooltip
{
get { return _imagetooltip; }
set { _imagetooltip = value; }
}
public string Image
{
get { return _image; }
set { _image = value; }
}
public int? RelevantQualityId { get; set; }
protected void StoreQualityInfo(Quality q)
{
PyramidNumberIncreaseLimit = q.PyramidNumberIncreaseLimit;
RelevantQualityId = q.Id;
RelevantQualityName = q.Name;
ImageTooltip = "<strong>" + q.Name + "</strong><br/>" + q.Description + "<br>" +
q.EnhancementsDescription;
Image = q.Image;
}
public virtual IResultPresentation GetPresentation(IResultFormatter formatter)
{
return formatter.GetResult(this);
}
}
UserController - Working example.
public partial class UserController : Controller
{
private readonly IMessageDisplayFetch _messageDisplayFetch;
public UserController(IMessageDisplayFetch messageDisplayFetch)
{
_messageDisplayFetch = messageDisplayFetch;
}
public virtual ActionResult MessagesForStoryletWindow()
{
var activeChar = _us.CurrentCharacter();
IEnumerable<IResultPresentation> messages;
messages = _messageDisplayFetch.FlushMessagesAsPresentations(_storyFormatter);
var vd = new MessagesViewData(messages)
{
Character = new CharacterViewData(activeChar),
};
return View(Views.Messages, vd);
}
}

Check a property is unique in list in FluentValidation

I am trying to ensure that a list has unique SSN's. I am getting the "Property name could not be automatically determined for expression element => element. Please specify either a custom property name by calling 'WithName'" error. Would we know what I am doing wrong here?
using FluentValidation;
using FluentValidation.Validators;
public class PersonsValidator : AbstractValidator<Persons>
{
public PersonsValidator()
{
this.RuleFor(element => element)
.SetValidator(new SSNNumbersInHouseHoldShouldBeUnique<Persons>())
.WithName("SSN");
.WithMessage("SSN's in household should be unique");
}
}
public class SSNNumbersInHouseHoldShouldBeUnique<T> : PropertyValidator
{
public SSNNumbersInHouseHoldShouldBeUnique()
: base("SSN's in household should be unique")
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
var persons = context.Instance as Persons;
try
{
if (persons == null)
{
return false;
}
var persons = persons.Where(element => element.SSN.Trim().Length > 0);
var allSSNs = persons.Select(element => element.SSN.Trim());
if (allSSNs.Count() > allSSNs.Distinct().Count())
{
return false;
}
return true;
}
catch (Exception ex)
{
return false;
}
}
}
public class Persons : List<Person>
{}
public class Person
{
public string SSN{ get; set; }
}
I was using FluentValidation version 4.6. According to Jeremy Skinner(author of FluentValidation), I need to be on at least 5.6 to be able to use model-level rules (like RuleFor(element => element)).
As a workaround, I added this validation on the actual class itself instead of creating a validation class. Hope this helps someone.
using FluentValidation;
using FluentValidation.Results;
public class Persons : List<Person>
{
public void ValidateAndThrow()
{
var errors = new List<ValidationFailure>();
try
{
var persons = this.Where(element => element.SSN.Trim().Length > 0);
var allSSNs = persons.Select(element => element.SSN.Trim());
if (allSSNs.Count() > allSSNs.Distinct().Count())
{
var validationFailure = new ValidationFailure("UniqueSSNsInHouseHold", "SSN's in a household should be unique");
errors.Add(validationFailure);
}
}
catch (Exception ex)
{
}
if (errors.Any())
{
throw new ValidationException(errors);
}
}
}

How can I write these methods in a more generic way in c#?

I have the following class hierarchy:
EstadoBaseMO (parent)
EstadoSAMO(EstadoBaseMO child)
EstadoGesDocMO(EstadoBaseMO child)
SolicitudBasePresenter(parent)
SolicitudGesDocPresenter(SolicitudBasePresenter child)
SolicitudSAPresenter(SolicitudBasePresenter child)
EstadoBaseBO(parent)
EstadoGesDocBO(EstadoBaseBO child)
EstadoSABO(EstadoBaseBO child)
I need to implement a method called SaveNewDetailStates, with the following implementation in SolicitudBasePresente is
public bool SaveNewDetailStates(List<EstadoBaseMO> estados)
{
bool result = true;
if (estados.Any())
{
try
{
EstadoGesDocBO bo = new EstadoGesDocBO();
foreach (var estado in estados)
{
var savedState = bo.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
SolicitudGesDocPresenter.SaveNewDetailStates implementation
public bool SaveNewDetailStates(List<EstadoGesDocMO> estados)
{
bool result = true;
if (estados.Any())
{
try
{
EstadoGesDocBO bo = new EstadoGesDocBO();
foreach (var estado in estados)
{
var savedState = bo.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
SolicitudSAPresenter.SaveNewDetailStates implementation
public bool SaveNewDetailStates(List<EstadoSAMO> estados)
{
bool result = true;
if (estados.Any())
{
try
{
EstadoSABO bo = new EstadoSABO();
foreach (var estado in estados)
{
var savedState = bo.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
As you can see, the code is exactly the same with two differences, in SolicitudSAPresenter I'm using EstadoSAMO and EstadoSABO classes, similar in SolicitudGesDocPresenter.
Things to know:
I don't really need an implementation of SolicitudBasePresenter.SaveNewDetailStates
I tried to convert the parent method(SolicitudBasePresenter.SaveNewDetailStates) to an abstract method, but then, the SAPresenter and GesDocPresenter can't use override because they need to implement the same signature (and it's not the same..), besides, soon after I realized I need a concrete implementation of SolicitudBasePresenter, so it shouldn't be an abstract class (similar happens with a virtual method)
Maybe the use of generics can solve that problem, but I'm still not used to them. I tried with something like SaveNewDetailStates<T,K>(List<T> estados), but then I'm lost and I don't know what else can I do.
What is the best approach for writing this code?
The only solution I have is to delete the SaveNewDetailStates from parent presenter, and write the concrete implementation in children and then everything is fine but...I don't think that's even a solution for a good developer..
You need to use Generics. Define the class EstadoBaseMO<T> and then use the type T in your save method.
public bool SaveNewDetailStates(List<T> estados)
Your child classes can then (for example) extend EstadoBaseMO<SolicitudBasePresenter>.
There are lots of generics tutorials online, have a look at some of them.
https://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx
you can use Generics but you still need to use Interfaces to implement what you need, but you can do it only with Interfeces similar to this, I made separate IEstadoState and IEstadoMO to make it more clear if you don't need additional fields in your logic you can make one interface instead of these two
public interface IEstadoState
{
int Id { get; set; }
}
public interface IEstadoMO
{
int Id { get; set; }
}
public interface IEstadoBO
{
IEstadoState Insert(IEstadoMO estadoMO);
}
public class SolicitudBasePresenter
{
public virtual bool SaveNewDetailStates(List<IEstadoMO> estados, IEstadoBO estadoBO)
{
bool result = true;
if (estados.Any())
{
try
{
foreach (var estado in estados)
{
var savedState = estadoBO.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
}
public class SolicitudGesDocPresenter : SolicitudBasePresenter { }
public class SolicitudSAPresenter : SolicitudBasePresenter { }
if you prefer to use Generic or don't want to pass second parameter to method here is how it will look
public class SolicitudBasePresenter<T1, T2> where T1 : IEstadoMO where T2 : IEstadoBO, new()
{
public bool SaveNewDetailStates(List<T1> estados)
{
bool result = true;
if (estados.Any())
{
try
{
foreach (var estado in estados)
{
var estadoBO = new T2();
var savedState = estadoBO.Insert(estado);
result &= ((savedState != null) && (savedState.Id != estado.Id));
}
}
catch (Exception ex)
{
result = false;
}
}
return result;
}
}
public class EstadoState : IEstadoState
{
public int Id {get; set;}
}
public class EstadoBaseMO : IEstadoMO
{
public int Id { get; set; }
}
public class EstadoBaseBO : IEstadoBO
{
public IEstadoState Insert(IEstadoMO estado) { return new EstadoState(); }
}
public class EstadoSAMO : EstadoBaseMO { }
public class EstadoGesDocMO : EstadoBaseMO { }
public class EstadoGesDocBO : EstadoBaseBO { }
public class EstadoSABO : EstadoBaseBO { }
public class SolicitudGesDocPresenter : SolicitudBasePresenter<EstadoGesDocMO, EstadoGesDocBO> { }
public class SolicitudSAPresenter : SolicitudBasePresenter<EstadoSAMO, EstadoSABO> { }
your method call will be
var docPresenter = new SolicitudGesDocPresenter();
docPresenter.SaveNewDetailStates(new List<EstadoGesDocMO>());
also you can declare children like this
public class SolicitudGesDocPresenter<T1, T2> : SolicitudBasePresenter<T1, T2> where T1 : IEstadoMO where T2 : IEstadoBO, new() { }
public class SolicitudSAPresenter<T1, T2> : SolicitudBasePresenter<T1, T2> where T1 : IEstadoMO where T2 : IEstadoBO, new() { }
you'll call it in this way
var docPresenter = new SolicitudGesDocPresenter<EstadoGesDocMO, EstadoGesDocBO>();
docPresenter.SaveNewDetailStates(new List<EstadoGesDocMO>());

How can I make this exception handling code adhere to the DRY principle?

I have a particular situation where I need to trap exceptions and return an object to the client in place of the exception. I cannot put the exception handling logic at a higher level i.e. wrap Foo within a try clause.
It's best to demonstrate with some sample code. The exception handling logic is clouding the intention of the method and if I have, many methods of similar intent, in the Foo class, I find myself repeating most of the catch logic.
What would be the best technique to wrap the common exception functionality in the code below?
public class Foo
{
public Bar SomeMethodThatCanThrowExcepetion()
{
try
{
return new Bar().Execute();
}
catch(BazException ex)
{
WriteLogMessage(ex, Bar.ErrorCode);
return new Bar() { ErrorMessage = ex.Message, ErrorCode = Bar.ErrorCode;}
}
}
public Baz SomeMethodThatCanThrowExcepetion(SomeObject stuff)
{
try
{
return new Baz(stuff).Execute();
}
catch(BazException ex)
{
WriteLogMessage(ex, Baz.ErrorCode);
return new Baz() { ErrorMessage = ex.Message, ErrorCode = Baz.ErrorCode;}
}
}
}
Updated per Lee's comment
One possibility is to use a generic helper method. Something like this:
T TryExecute<T>(Func<T> action, int ErrorCode)
{
try
{
return action();
}
catch (Exception ex)
{
result = Activator.CreateInstance<T>();
typeof(T).GetProperty("ErrorMessage").SetValue(result, ex.Message, null);
typeof(T).GetProperty("ErrorCode").SetValue(result, ErrorCode, null);
return result;
}
return result;
}
If you can modify Bar and Baz, then you could improve this by placing a requirement on T:
public interface IError
{
public string ErrorMessage { get; set; }
public int ErrorCode { get; set; }
}
T TryExecute<T>(Func<T> action, int ErrorCode) where T : IError
{
try
{
return action();
}
catch (Exception ex)
{
result = Activator.CreateInstance<T>();
result.ErrorMessage = ex.Message;
result.ErrorCode = ErrorCode;
return result;
}
}
Then you'd use:
return TryExecute<Bar>(new Bar().Execute, Bar.ErrorCode);
And:
return TryExecute<Baz>(new Baz(stuff).Execute, Baz.ErrorCode);
That may or may not be an over-abstraction for your particular design; the devil is in the details.
How about a base class:
public class ErrorCapable {
public string ErrorMessage { set; get; }
public int ErrorCode { set; get; }
public static ErrorCapable<T> Oops(Exception exc) where T : ErrorCapable, new() {
// Code for logging error here
return new T() { ErrorMessage = exc.Message, ErrorCode = exc.ErrorCode };
}
}
public class Bar : ErrorCapable {
//...
}
public class Baz : ErrorCapable {
//...
}
Then in the catch, just use, for example:
return ErrorCapable.Oops<Bar>(ex);
Do you really need the explicit logging in every method? Instead of having the exception logic in every method, have one handler in your Main method of the program and handle the exceptions generically.
Also, you don't need to return an arbitrary object from a catch block should you really need the logging there, simply use throw; to let it wander up the stack.
I think the best you can do is something like:
public T TryOrDefault<T>(Func<T> act, int errorCode, Func<BazException, T> onError)
{
try
{
return act;
}
catch(BazException ex)
{
WriteLogMessage(ex, errorCode);
return onError(ex);
}
}
then you can write your other methods in terms of it:
public Bar SomeMethodThatCanThrowException()
{
Bar b = new Bar();
return ExecOrDefault(() => b.Execute(), Bar.ErrorCode, ex => new Bar { ErrorMessage = ex.Message, ErrorCode = Bar.ErrorCode });
}

Entity Framework on different project - saving?

I have an established SQL Server database setup. I then generated an Entity Framework model in a Console Application to test some selecting, editing and adding to the database. All went well.
I am now moving more towards my final physical design of my WinForms and WebApp. So, I have decided to do the project in separate projects. I moved the Entity Framework to a Data project, I created a Services project, and I still have my console app as a test application (All in the same solution).
I have a ClassLib with data transfer objects to pass between my layers. So my GUI layer and Service layer don't know of the Entity Framework. I have helper methods in my EF project that convert the EF data into List etc...
Eg of a helper method:
using ClassLib;
namespace Data
{
public class PayeeDAL : EntityBase
{
public static List<PayeeDto> GetPayees()
{
var payees = (from payee in Db.payees
select payee).ToList();
List<PayeeDto> reply = new List<PayeeDto>();
foreach (var pa in payees)
{
PayeeDto p = new PayeeDto
{
PayeeId = pa.payee_id,
Name = pa.name,
Deleted = pa.deleted == null
};
reply.Add(p);
}
return reply;
}
}
}
And my data transfer object looks like this:
namespace ClassLib
{
public class PayeeDto
{
public int PayeeId { get; set; }
public string Name { get; set; }
public bool Deleted { get; set; }
}
}
So, my selection is working well with this design... but... have no idea how to handle saving.
In my console application, when the EF was available to me, I did this:
db.AddToaccount_transaction(ac);
account_transaction_line atl = new account_transaction_line
{
amount = amount,
cost_centre =
db.cost_centre.FirstOrDefault(
cc => cc.cost_centre_id == costcentreid),
sub_category =
db.sub_category.First(
sc => sc.sub_category_id == subcategoryId),
account_transaction = ac,
budget = db.budgets.FirstOrDefault(b => b.budget_id == budgetid)
};
db.AddToaccount_transaction_line(atl);
}
db.SaveChanges();
But now I don't have access to .AddTo.... and .SaveChanges... In my Console app, I'd create a parent object, and then add a few child objects... and then add the child objects to the parent object, and save.
But how would this be done in my new structure? I'm thinking I'd have a Save method in each of my helper classes... And then pass a List<> of the child objects, along with a single Parent class to the save method... and then transfor the Dtos to EF models, and then save it that way?
Is that an acceptable plan?
I only use DTO objects to transfer data from A to B. The updating, adding, removing etc., I always encapsulate in Commands (Command Pattern).
Retrieving data I do similarily with "Helper" classes.
Example of command pattern:
The base classes:
namespace Busker.Data.Commands
{
/// <summary>
/// The 'Command' abstract class
/// </summary>
public abstract class Command
{
private string message = "";
public string Message
{
get { return message; }
set { message = value; }
}
private bool success = false;
public bool Success
{
get { return success; }
set { success = value; }
}
private Validator validator = new Validator();
public Validator Validator
{
get { return validator; }
set { validator = value; }
}
private CommandStatusCode statusCode = CommandStatusCode.OK;
public CommandStatusCode StatusCode
{
get { return statusCode; }
set { statusCode = value; }
}
public LoggingLevel LoggingLevel = LoggingLevel.Debug;
//public BuskerContext BuskerContext;
public bool IsValid()
{
if (validator.Errors.Count > 0)
return false;
return true;
}
public abstract void Execute();
public void FailedSubCommand(Command cmd)
{
this.Success = cmd.Success;
this.Message = cmd.message;
}
}
}
namespace Busker.Data.Commands
{
public class Invoker
{
private Command command;
public Command Command
{
get { return command; }
set { command = value; }
}
public void SetCommand(Command command)
{
this.Command = command;
}
public virtual void ExecuteCommand()
{
if (command == null)
throw new Exception("You forgot to set the command!!");
try
{
log(this.command.GetType().Name + " starting execution ");
command.Execute();
if (!command.Success)
{
log(this.command.GetType().Name + " completed execution but failed. Message: " + command.Message + " " + command.StatusCode.ToString());
}
else
log(this.command.GetType().Name + " completed execution. Success!");
}
catch (Exception ex)
{
command.StatusCode = CommandStatusCode.Error;
Loggy.AddError("An unhandled error was caught in " + this.command.GetType().Name + ": " + ex.Message, ex);
command.Message = ex.ToString();
//throw;
}
}
private void log(string msg)
{
switch (command.LoggingLevel)
{
case Busker.Data.Constants.LoggingLevel.Debug:
Loggy.Debug(msg);
break;
case Busker.Data.Constants.LoggingLevel.Off:
break;
default:
Loggy.Add(msg);
break;
}
}
public virtual void ExecuteLinqCommand()
{
this.ExecuteCommand();
}
}
}
namespace Busker.Data.Commands
{
public static class Extensions
{
/// <summary>
/// Executes the command using the default invoker.
/// </summary>
/// <param name="aCommand"></param>
public static void Invoke(this Command aCommand)
{
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace();
System.Reflection.MethodBase m = stackTrace.GetFrame(1).GetMethod();
String strMethodName = m.DeclaringType.Name + "." + m.Name;
try
{
Invoker invoker = new Invoker();
invoker.SetCommand(aCommand);
invoker.ExecuteCommand();
}
catch (Exception ex)
{
Loggy.AddError("An error occured in Extensions.Invoke. + " + strMethodName ,ex);
throw ex;
}
}
}
Implementation Example:
namespace Busker.Data.Commands.Message
{
public class CreateMessageCommand :Command
{
public CreateMessageCommand (int from, int to, string title, string body)
{
// set private variable..
}
public override void Execute()
{
// Do your stuff here
be.SaveChanges();
this.Success = true;
}
}
}
Usage:
CreateMessageCommand cmd = new CreateMessageCommand (...);
//Don't use the execute method of the command
//the invoker, because implemented as an extension can be exchange in different
//environments
cmd.Invoke();

Categories