I have a requirement of compose the log message through the path taken by a code in a user click. Let me give an example:
Imagine the classical example: A user clicks in a button in a View, that calls code from the Business Layer that call code from Data Access Layer, that returns data to the Business, that return to a View.
I want to compose my log message through these layers. The caller method (in a View) that started the whole process will receive the full message. Here are some code sample just to help me explain what i am trying to achieve.
public void ViewMethod()
{
try
{
BussinessMethod();
}
catch (Exception ex)
{
Logger.Enqueue("exception occured");
Logger.Print();
}
}
public void BussinessMethod()
{
try
{
DataAcessMethod();
}
catch (Exception ex)
{
Logger.Enqueue("exception occured in the bussiness method")
}
}
public void DataAcessMethod()
{
try
{
// some code that executes an SQL command
// Log the SQL Command 1
// Log the SQL Command 2 and do on...
}
catch (Exception ex)
{
Logger.Enqueue("Error occurred, sqls executed are ...", sqlExecuted);
}
}
EDIT: The reason i am needing it is that i need to log all the SQL's executed in the whole process. If an error occurs in any point of the whole process, the user cant be warned, i need to store as much as possible information becouse the support technician will need it later.
My question is if there is any design pattern to develop it or passing a Logger reference across the "layers" are acceptable?
I would do something like this
public class Context
{
[ThreadStatic]
private static LogStore _store;
public static Log(....)
{
.....
}
}
public void ViewMethod()
{
var response = BussinessMethod();
if (response.Status = ResponseStatus.Success)
// do something with response.Data
else
// show message?
}
public BusinessMethodResponse BussinessMethod()
{
var response = new BusinessMethodResponse() {Status = ResponseStatus.Failure};
SomeData data;
try
{
data = DataAcessMethod();
}
catch (Exception ex)
{
Context.Log(....);
response.Message = "Data retrieval failed";
return response;
}
try
{
// massage the data here
response.Status = ResponseStatus.Success;
response.Data = myMassagedData;
}
catch (Exception ex)
{
Context.Log(....);
response.Message = "Something failed";
}
return response;
}
public void DataAcessMethod()
{
// some code that executes an SQL command
}
What this do? Now you can call your business objects from MVC, WPF, WinForms, Web Forms, etc...
Related
According to Microsoft's recommendation, throwing and catching should not be used for the normal logic of the program.
Minimize exceptions
As part of a ASP.Net core clean architecture project (with 3 Layers Generic Repositories - BL Services - Controllers), how should the error handling and the results be designed and implemented?
Should a struct or a global result class be used for all Api Controllers and BL services?
Is it enough if the errors and the results are encapsulated in a struct?
Example of result class in the WebApi project:
public class ExampleResult<T>
{
public ExampleResult(T value, string message, bool success)
{
(...)
}
}
Controller:
public ActionResult<ExampleResult<NewResourceDto>> Post([FromBody] NewResourceDto myNewResource)
{
try
{
if(!Validate(myNewResource))
return new ExampleResult(null, "some business logic validate failed", true);
ExampleResult result = _service.TrySaveMyNewResource(myNewResource);
return result;
}
catch (Exception ex)
{
// Log the exception here...
return new ExampleResult(null, "some message" + ex, false);
}
}
The Angular Client then validates if the value is null and/or whether the success is true or false.
The message contains the error messages.
The http status will be 200 (no matter if success or not).
How are the exceptions minimized elegantly?
targeting the best practice in .Net Core or any other framework you need to return a common model of all of your apis that holds all the date returned from your api in case if it's a result or an error then in your angular service you should check on your returned object keys which is your base model.
public class ErrorModel
{
public ErrorModel()
{
ErrorMessages = new List<string>();
}
public List<string> ErrorMessages { get; set; }
public Exception Exception { get; set; }
}
public class BaseModel
{
public BaseModel()
{
Error = new ErrorModel();
}
public ErrorModel Error { get; set; }
}
public class BaseModel<T>: BaseModel
{
public BaseModel()
{
Error = new ErrorModel();
}
public bool HasError => Error.ErrorMessages.Count > 0 || Error.Exception != null;
public T Result { get; set; }
}
then your api should look like that
public ActionResult<BaseModel<dynamic>> Post([FromBody] NewResourceDto myNewResource)
{
try
{
ExampleResult result = _service.TrySaveMyNewResource(myNewResource);
return OK( new BaseModel<dynamic>()
{
Result=result
});
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, new BaseModel<dynamic>()
{
Error = new ErrorModel()
{
ErrorMessages = new List<string>()
{
ex.Message,
"your message 2",
"your message 3"
},
Exception = ex
}
});
}
}
then in your angluar service you shold check on your response.hasError and displays your data according to it.
I agree that throwing Exceptions should not be used as signaling in the system. Maybe I don't understand your question about the returning a struct or a global result class. Seems like a bad idea. Especially, don't return HTTP OK 200 if something goes south.
Keep your Web API controllers as thin and dumb as possible
Wrap your Web API controller method methods in a try-catch so you always return HTTP Internal Server Error 500 on an unexpected error
Example of a controller method:
public IActionResult Post([FromBody] NewResourceDto myNewResource)
{
try
{
_service.TrySaveMyNewResource(myNewResource);
return StatusCode(201);
}
catch (Exception ex)
{
// Log the exception here...
return StatusCode(500);
}
}
I am working on a function to send console window output to a discord channel.
i managed to make it work but i can't get the main goal of the function.
i want to get the output directly from the console instead of getting the output from the logger class which i have.
i have a separate logger class which controls all logging, that would be standard way but i have never tried to get the output directly from console.
i have searched and found Console.Out() method but i guess its mainly used for writing to text file.
i am using Discord.Net.
here is the sample function which i call from the logger class.
public sealed class LogToChannel : DiscordHandler
{
public static async Task SendToChannel(string message)
{
try
{
if (!IsServerOnline || string.IsNullOrEmpty(message) || string.IsNullOrWhiteSpace(message))
{
return;
}
string shortDate = DateTime.Now.ToShortDateString();
string shortTime = DateTime.Now.ToShortTimeString();
string LogFormat = $"[{shortDate} {shortTime}] {message}";
await Task.Delay(200).ConfigureAwait(false);
await Client.GetGuild(4646556464646464546).GetTextChannel(546464654646546465).SendMessageAsync(LogFormat).ConfigureAwait(false);
}
catch (Exception ex)
{
if(ex is NullReferenceException)
{
throw;
}
else
{
SGF.SGFLogger.LogException(ex);
return;
}
}
}
}
Out of need have created application exception which wraps a MongoDuplicateKeyException and throwing that exception like below
Public class AppException : Exception
{
// all constructor implementation
public int ErrorCode { get; set; }
public string AppMessage { get; set; }
}
In method catching and throwing exception
public async Task<Response> Method1(parameter ...)
{
try
{
//some insert/update operation to DB
return <instance of Response>;
}
catch(MongoduplicateKeyException ex)
{
var exception = new AppException(ex.Message, ex)
{
ErrorCode = 22,
AppMessage = "some message",
};
throw exception;
}
}
Method that calls Method1() above
try
{
//some other operation
var response = await Method1();
}
catch(AppException ex)
{
SomeOtherLoggingMethod(ex, other parameter);
}
catch(Exception ex)
{
SomeMethod(ex, other parameter);
}
Surprisingly the catch(AppException ex) catch block never gets catched even though am throwing an AppException from Method1(). It always catch the generic catch block catch(Exception ex).
After debugging, found that in catch(Exception ex) catch block the exception type ex.GetType() is actually a WriteConcernException type (MongoduplicateKeyException : WriteConcernException).
So essentially that specific catch block not hitting cause the exception type is not AppException rather WriteConcernException But
Not sure why is it so? am I missing something obvious here? Please suggest.
You found the answer while debugging. The catch(AppException ex) block is not executed because public async Task<Response> Method1 does not throw an AppException it throws a WriteConcernException.
The API shows a WriteConcernException is the superclass of DuplicateKeyException so the catch block in Method1 is not hit and the exception bubbles up to the 2nd catch block in the caller.
So if you update your code to catch the appropriate exception it should work as you intend.
public async Task<Response> Method1(parameter ...)
{
try
{
//some insert/update operation to DB
return <instance of Response>;
}
catch (MongoServerException mse)
...
I am trying to unit test my code to see if I try to view an account's details without a sessionKey, it will throw an exception. The unit test will go and execute the statement in the try-catch and despite knowing an exception will occur, it lists the test as successful even though Assert should be false. Assert is reached in similar functions, but not always. What would be the cause of the problem?
Original Function
/// <summary>
/// Displays the account details to the user
/// </summary>
/// <returns>HttpResponseMessage deserialized into AccountResponses object</returns>
public async Task<AccountResponse> Details()
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Session-Key", sessionKey);
try
{
HttpResponseMessage response = await client.GetAsync(_baseUrl + "/Account/Details");
response.EnsureSuccessStatusCode();
string details = await response.Content.ReadAsStringAsync();
AccountResponse temp = JsonConvert.DeserializeObject<AccountResponse>(details);
return temp
}
catch (HttpRequestException ex)
{
throw ex;
}
}
Working Live Unit Test Function
[TestCategory("Account/Logon")]
[TestMethod]
public void LogOnNegativeBadPasswordTest()
{
try
{
string sessionKey = dmWeb.Account.LogOn(new DMWeb_REST.AccountLogOn { Password = "test#pasasdfasfsword" }).GetAwaiter().GetResult().ToString();
}
catch (HttpRequestException ex)
{
Assert.IsTrue(ex.Message.Contains("400"));
}
}
Not Working Live Unit Test Function
[TestCategory("Account/Details")]
[TestMethod]
public void DisplayDetailsNegativeNoSessionKeyTest()
{
try
{
string details = dmWeb.Account.Details().GetAwaiter().GetResult().ToString();
}
catch (HttpRequestException ex)
{
Assert.IsTrue(ex.Message.Contains("401"));
}
}
The test will be treated as successful as long as no errors are thrown. If no error is being caught in the catch block, this almost definitely means that no error was thrown by the code you're testing.
So place an Assert.Fail() after the statement that's supposed to throw an error:
public void TestMethod()
{
try
{
string details = ThingIAmTesting();
// shouldn't get here
Assert.Fail();
}
catch (Exception ex)
{
Assert.IsTrue(ex.Message.Contains("401");
}
}
WPF, Excel AddIn, C#,
I have multiple asychronous calls to get data from web service on main thread, then in call back,
I will plot the data in Excel. I tracked call back and they run on main thread, too.
but I still get COMException 0x800AC472, googled and it seems this is a multi-thread issue.
but I am confused why this happened.
I think there is only one main thread and since all callback are run on main thread and there is no reason to have the exception?
Edit:
On main UI thread, ribbon/button is clicked, it will call web service BuildMetaData,
once it is returned back, in its callback MetaDataCompleteCallback, another web service call is sent
Once it is returned back, in its callback DataRequestJobFinished, it will call plot to plot data on Excel. see below
On Main UI class:
Btn_Click()
{
...
_reportObjs[index].GenerateReport();
}
on Class to GenerateReport
public void GenerateReport()
{
Request.ParseFunction();
Request.MetacompleteCallBack = MetaDataCompleteCallback;
Request.BuildMetaData();
}
public void MetaDataCompleteCallback(int id)
{
try
{
if (Request.IsRequestCancelled)
{
Request.FormulaCell.Dispose();
return;
}
ErrorMessage = Request.ErrorMessage;
if (string.IsNullOrEmpty(Request.ErrorMessage))
{
_queryJob = new DataQueryJob(UnityContainer, Request.BuildQueryString(), DataRequestJobFinished, Request);
}
else
{
ModifyCommentOnFormulaCellPublishRefreshEvent();
}
}
catch (Exception ex)
{
ErrorMessage = ex.Message;
ModifyCommentOnFormulaCellPublishRefreshEvent();
}
finally
{
Request.MetacompleteCallBack = null;
}
}
public void DataRequestJobFinished(DataRequestResponse response)
{
Dispatcher.Invoke(new Action<DataRequestResponse>(DataRequestJobFinishedUI), response);
}
public void DataRequestJobFinished(DataRequestResponse response)
{
try
{
if (Request.IsRequestCancelled)
{
return;
}
if (response.status != Status.COMPLETE)
{
ErrorMessage = ManipulateStatusMsg(response);
}
else // COMPLETE
{
// TODO: Convert this into factory pattern
var tmpReq = Request as DataRequest;
if (tmpReq == null) return;
new VerticalTemplate(tmpReq, response, IsOffice2003).Plot();
}
}
catch (Exception e)
{
ErrorMessage = e.Message;
MIMICShared.Helper.LogError(e);
}
finally
{
//if (token != null)
// this.UnityContainer.Resolve<IEventAggregator>().GetEvent<DataQueryJobComplete>().Unsubscribe(token);
ModifyCommentOnFormulaCellPublishRefreshEvent();
Request.FormulaCell.Dispose();
}
}
on plot class
public void Plot()
{
...
attributeRange.Value2 = headerArray;
DataRange.Value2 = ....
DataRange.NumberFormat = ...
}
I saw this stackoverflow.com/questions/5246288/errormessage-in-excel, social.msdn.microsoft.com/forums/en-US/vsto/thread/… It seems there is no solution to the issue except wait/retry.
THis post talks about how to check if Excel is in edit. http://www.add-in-express.com/creating-addins-blog/2011/03/23/excel-check-user-edit-cell/