How to throw Exception from WebAPI - c#

I have business logic which has throw exception, which I need to transfer to my api controller and show when my webapi fails to read. I have tray catch in all place. In Business Logic`
public static Models.User Login(Models.Login model)
{
try
{
using (var db = new Data.TPX5Entities())
{
var query = (from a in db.User
where a.UserID == model.UserName || a.UserCode == model.UserName || a.UserName == model.UserName
select new Models.User
{
EMail = a.EMail,
IsUsed = a.IsUsed,
Memo = a.Memo,
MobilePhone = a.MobilePhone,
Password = a.Password,
Telephone = a.Telephone,
UserCode = a.UserCode,
UserID = a.UserID,
UserName = a.UserName
}).ToList();
if (query == null || query.Count == 0)
{
throw new Exception(#LanguageHelper.GetSystemKeyValue(CultureHelper.GetCurrentCulture(), "/resource/Model/BLL_User_MSG_UserNotFound"));
}
else if (query.Count > 1)
{
throw new Exception(#LanguageHelper.GetSystemKeyValue(CultureHelper.GetCurrentCulture(), "/resource/Model/BLL_User_MSG_UserCodeRepeat"));
}
else
{
if (query[0].Password == model.Password)
{
return query[0];
}
else
{
throw new Exception(#LanguageHelper.GetSystemKeyValue(CultureHelper.GetCurrentCulture(), "/resource/Model/BLL_User_MSG_InCorrectPassword"));
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
then web api controller I use try catch again
[HttpPost]
public Models.User Login(Models.Login model)
{
Models.User mUser = null;
try
{
mUser = BusinessLogic.User.Login(model);
if (mUser == null)
throw new Exception("Object is null.");
}
catch(Exception ex)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(ex.Message, Encoding.UTF8), ReasonPhrase = "Login Exception" });
}
return mUser;
}
and then I call in my client I use try catch to check again
private void btnLogin_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty( txtUser.Text))
{
TPX.Core.MessageBoxHelper.ShowError(Core.LanguageHelper.GetSystemKeyValue(GlobalParameters.Language, "/resource/Message/MS_FormLogin_Error_UserEmpty"));
return;
}
try
{
//登录系统
string md5Password = TPX.Core.Security.MD5.GetMD5(txtPassword.Text);
TPX.Models.Login mLogin = new TPX.Models.Login();
mLogin.UserName = txtUser.Text.Trim();
mLogin.Password = md5Password;
//Retrieve User Information
string itemJson = Newtonsoft.Json.JsonConvert.SerializeObject(mLogin);
string userURL = GlobalParameters.Host + "api/User/Login";
using (System.Net.WebClient webClient = new System.Net.WebClient())
{
webClient.Headers["Content-Type"] = "application/json";
webClient.Encoding = Encoding.UTF8;
string sJson = webClient.UploadString(userURL, "POST", itemJson);
TPX.Models.User myDeserializedObj = (TPX.Models.User)Newtonsoft.Json.JsonConvert.DeserializeObject(sJson, typeof(TPX.Models.User));
ClientContext.Instance.UserID = myDeserializedObj.UserID;
ClientContext.Instance.UserCode = myDeserializedObj.UserCode;
ClientContext.Instance.UserName = myDeserializedObj.UserName;
ClientContext.Instance.Password = myDeserializedObj.Password;
}
DialogResult = System.Windows.Forms.DialogResult.OK;
}
catch (WebException ex)
{
TPX.Core.MessageBoxHelper.ShowException((Core.LanguageHelper.GetSystemKeyValue(GlobalParameters.Language, "/resource/Message/MS_FormLogin_Ex_LoginError")),ex);
}
}
When I login with wrong credential need to throw error. Now I am getting error "The remote Server return error:(500)Internal Server Error', Instead I want to throw exact error which my business logic throw. Thanks
`

Do not throw 500 internal server error but try and communicating using specific http codes. In your case you want to communicate login failure so tell your client that specifically.
Either use:
throw new HttpResponseException(HttpStatusCode.Unauthorized);
Or, a custom message like this:
var msg = new HttpResponseMessage(HttpStatusCode.Unauthorized) {
ReasonPhrase = "whatever you want it!" };
hrow new HttpResponseException(msg);

your business layer and your api are two different things.
you don't throw errors from your api unless something really bad happened with your own code.
The api always returns meaningful http codes and that's how the clients know what's going on.
Example:
[HttpPost]
public IHttpActionResult Login(Models.Login model)
{
var mUser = BusinessLogic.User.Login(model);
if (mUser == null)
return NotFound();
return Ok(mUser);
}
you are now returning something meaningful which makes sense to a client and you are actually helping them understand what's going on.
There are multiple ways to return data, this is only one of them.
Avoid throwing errors, it is expensive in terms of resources used and the more users you have the worse it will get.
You can have your business layer return a message in form of a string and then return that as a result of the API call and the other response shows you how.

Related

Get EventMessage from message in MS Graph API with C#

I am trying to Get EventMessage from Message in MS Graph API with C# but every time it is showing type as a message instead of EventMessage. Below are the code:-
public static Graph.MailFolderMessagesCollectionPage ReadInbox()
{
GetAuthenticatedClient();
var result = new Graph.MailFolderMessagesCollectionPage();
List<Graph.QueryOption> options = new List<Graph.QueryOption>
{
new Graph.QueryOption("$expand","microsoft.graph.eventMessage/event"),
new Graph.QueryOption("$filter","isread eq false")
};
try
{
var response = graphClient.Me.MailFolders.Inbox.Messages.Request(options).OrderBy("receivedDateTime DESC").GetAsync();
result = response.Result as Graph.MailFolderMessagesCollectionPage;
}
catch (Exception ex)
{ }
Call the above method ReadInbox to get type and perform some action.
var appointments = ReadInbox();
if (appointments != null)
{
foreach (dynamic request in appointments)
{
try
{
if (request.GetType().Name.Contains("EventMessage"))
{
}
else if (request.GetType().Name == "Message")
{
}
}
catch (Exception ex)
{
}
}
}
Use the IsInstanceOfType method to identify if its an eventMessage. You can also remove the expand option from the query option since eventMessages are fetched anyway as part of the get Messages call.
if (appointments != null)
{
foreach (dynamic request in appointments)
{
try
{
if (typeof(EventMessage).IsInstanceOfType(request))
{
Console.WriteLine("Is an event");
Console.WriteLine(request);
}
}
catch (Exception ex)
{
}
}
}

ModelState.AddModelError is setup to display Canned message instead of real Error

In my website i had a group of people working on my site and i have this code that they put a canned message in for an error. When i debug the code it is actually a different error but displays this canned message. For instance when i put the information in the form i used an email address that already exists in the database but it is showing a message to check the password requirements. How can this be fixed to show the actual error. To me it also seems like there is a lot code going on in this that may not need to be or can be achieved cleaner Your thoughts?
Code of Post Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateCompanyUser(ExpandedUserDTO ExpandedUserDTO)
{
try
{
if (ExpandedUserDTO == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Email = ExpandedUserDTO.Email.Trim();
var UserName = ExpandedUserDTO.UserName.Trim();
var Password = ExpandedUserDTO.Password.Trim();
if (UserName == "")
{
throw new Exception("No Username");
}
if (Password == "")
{
throw new Exception("No Password");
}
// UserName is LowerCase of the Email
// UserName = Email.ToLower();
// Create user
var objNewAdminUser = new Models.ApplicationUser { UserName = UserName, Email = Email };
var AdminUserCreateResult = UserManager.Create(objNewAdminUser, Password);
if (AdminUserCreateResult.Succeeded == true)
{
string strNewRole = Convert.ToString(Request.Form["Roles"]);
if (strNewRole != "0")
{
// Put user in role
UserManager.AddToRole(objNewAdminUser.Id, strNewRole);
}
var viewModel = new Users();
{
viewModel.UsersId = Convert.ToString(Guid.NewGuid());
viewModel.Email = Email;
viewModel.FirstName = UserName;
viewModel.AspNetUsersId = objNewAdminUser.Id;
viewModel.CreatedDate = System.DateTime.Now;
viewModel.UpdatedDate = System.DateTime.Now;
};
UsersBusinessModels Login = new UsersBusinessModels();
var results = Login.insertUserWithougAsny(viewModel);
string[] roleRemove = new string[2] { "Administrator", "CompanyAdmin" };
ViewBag.Roles = GetAllRolesAsSelectList().Where(k => !roleRemove.Contains(k.Text)).ToList();
// return RedirectToAction();
Response.Redirect("/Customer/ManageUsers/" + User.Identity.GetUserId());
return PartialView();
}
else
{
ViewBag.Roles = GetAllRolesAsSelectList();
ModelState.AddModelError(string.Empty,
"Error: Failed to create the user. Check password requirements.");
return PartialView(ExpandedUserDTO);
}
}
catch (Exception ex)
{
ViewBag.Roles = GetAllRolesAsSelectList();
ModelState.AddModelError(string.Empty, "Error: " + ex);
string[] roleRemove = new string[2] { "Administrator", "CompanyAdmin" };
ViewBag.Roles = GetAllRolesAsSelectList().Where(k => !roleRemove.Contains(k.Text)).ToList();
return PartialView(ExpandedUserDTO);
}
}

Kendo Grid duplication message

I am using Kendo grid and I have stopped the grid from saving duplicate values as follows in create method:
var results = new List<ProviderTypeMasterViewModel>();
try
{
_logger.LogInformation("ProviderTypeMastersController ProviderType_Create Start");
foreach (var ProviderTypeMaster in ProviderTypeMasterList)
{
TblProviderTypeMaster ptm = new ProviderTypeMasterViewModel().ToModel(ProviderTypeMaster);
var provd = _context.TblProviderTypeMasters.Where(p => p.ProviderTypeName == ProviderTypeMaster.ProviderTypeName).ToList();
if (provd != null && provd.Count() == 0)
{
if (ProviderTypeMasterList != null && ModelState.IsValid)
{
string userID = GetUserID();
providerTypeMasterService.SaveProviderTypeMaster(ProviderTypeMaster, userID);
}
}
else
{
duplicate = true;
//Session["ErrMsg"] = "Already Exists";
//return RedirectToAction("ProviderType_Read", "ProviderTypeMasters");
}
}
_logger.LogInformation("ProviderTypeMastersController ProviderType_Create Complete");
}
catch (Exception e)
{
_logger.LogError("ProviderTypeMastersController ProviderType_Create Failed - " + e.Message);
}
return Json(results.ToDataSourceResult(request, ModelState));
And in the read method I have displayed the error message to the user as follows
try
{
if (duplicate == true)
{
TempData["ErroMsg"] = "Already Exists";
}
_logger.LogInformation("In ProviderTypeMastersController ProviderType_Read");
return Json(providerTypeMasterService.ListProviderTypeMaster().ToDataSourceResult(request));
}
catch (Exception e)
{
_logger.LogError("ProviderTypeMastersController ProviderType_Read Failed - " + e.Message);
}
return View();
The duplication process has stopped. But I am unable to show the error message to the user. Can anyone let me know what I should do where I have gone wrong. I have tried using ViewBag,ViewData,TempData.
This is my View
<div>
if (TempData["ErroMsg"] != null)
{
<p>#TempData["ErroMsg"].ToString()</p>
}
you can use DataBinding() and DataBound() function of kendo grid...these functions call in client side after Read method on server side..for example you can set a field and decision with this field

Setting Controls in Classes

I'm trying a booking system, I want to put controls on the booking aspect. I want to use If and then cases. I want to control in such a way that if number of booking is 4, then it will throw an exception and stop inserting in the database.
public ApiResult<TimeModelExtended> SaveBooking(Booking booking)
{
AchimotaGCDb repo = new AchimotaGCDb();
var result = new ApiResult<TimeModelExtended>();
try
{
booking.PlayDate = getPlayDate(booking.RefCode);
Int16 nb = getNbBooked(booking.RefCode);
if (nb == 4)
{
Exception ex = new Exception();
result.Successfull = 0;
result.InternalError = ex.Message;
result.Error = "Booking slot is full";
}
else if (nb == 0)
{
booking.BookingStatus = 1;//Booked already
}
else
{
booking.BookingStatus = 0;//Reservation already
}
repo.Insert(booking);
result.Successfull = 1;
result = GetOneteeTime(booking.RefCode);
}
catch (Exception ex)
{
result.Successfull = 0;
result.InternalError = ex.Message;
result.Error = "Error from server";
}
finally
{
repo.Dispose();
}
return result;
}
help to solve that.
If you want to throw an exception, you need to really throw it:
if (nb == 4)
{
throw new Exception("Booking slot is full.");
}
But I don't think throwing an exception is a good idea. Throwing an exception and validation is a different thing.
Here is my suggestion:
if (nb == 4)
{
return result = new ApiResult<TimeModelExtended>()
{
Successfull = 0,
InternalError = "Other messages",
Error = ""Booking slot is full."
};
}
This will return as result message that nothing will continue unless you satisfy that nb != 4

FacebookOAuthException was unhandled

I'm new in these things and I've been testing the api ...
and came to me a situation that is:
if the user changes the password of Facebook
the Access token is renewed ... and try to post the API Launches
an exception and the application crashes...
how to resolve this situation?
try {
FacebookApp app = new FacebookApp(FacebookToken);
var args = new Dictionary<string, object>();
args["message"] = "hi";
args["caption"] = "appcaption";
args["description"] = "appdescription";
args["name"] = "appname";
args["picture"] = "apppicture";
args["link"] = "applink";
app.ApiAsync((X) => { calback(X); }, null, "/me/feed", args, HttpMethod.Post);
}
catch (Exception ex) {
Uri url = new Uri("/MyFacebook.xaml", UriKind.Relative);
NavigationService.Navigate(url);
}
this is Api code, and it's crashing when throwing the OAuthExcepion at the line marked with "Exception HERE"
private static void ResponseCallback(IAsyncResult asyncResult, FacebookAsyncCallback callback, object state)
{
object result = null;
FacebookApiException exception = null;
try
{
var request = (HttpWebRequest)asyncResult.AsyncState;
var response = (HttpWebResponse)request.EndGetResponse(asyncResult);
using (Stream responseStream = response.GetResponseStream())
{
result = JsonSerializer.DeserializeObject(responseStream);
}
}
catch (FacebookApiException)
{
// Rest API Errors
throw;
}
catch (WebException ex)
{
// Graph API Errors or general web exceptions
exception = ExceptionFactory.GetGraphException(ex);
if (exception != null)
{
// Thow the FacebookApiException
throw exception;
}
throw; //Exception HERE
}
finally
{
// Check to make sure there hasn't been an exception.
// If there has, we want to pass null to the callback.
object data = null;
if (exception == null)
{
data = result;
}
#if SILVERLIGHT
callback(new FacebookAsyncResult(data, state, null, asyncResult.CompletedSynchronously, asyncResult.IsCompleted, exception));
#else
callback(new FacebookAsyncResult(data, state, asyncResult.AsyncWaitHandle, asyncResult.CompletedSynchronously, asyncResult.IsCompleted, exception));
#endif
}
}
thanks
The behavior of the SDK is intended. An exception is not "crashing" the application, but rather telling you when an error state has occurred. You are basically doing it correctly, but instead of catching Exception you should only catch FacebookOAuthException like this:
try {
FacebookApp app = new FacebookApp(FacebookToken);
var args = new Dictionary<string, object>();
args["message"] = "hi";
args["caption"] = "appcaption";
args["description"] = "appdescription";
args["name"] = "appname";
args["picture"] = "apppicture";
args["link"] = "applink";
app.ApiAsync("/me/feed", args, (X) => { calback(X); }, HttpMethod.Post);
}
catch (FacebookOAuthException) {
// This is where you would reauthorize the user or send them to a 'login' page
Uri url = new Uri("/MyFacebook.xaml", UriKind.Relative);
NavigationService.Navigate(url);
}
I would also suggest reading up on .Net exception handling to give you a better understanding of when and why they are used. http://msdn.microsoft.com/en-us/library/ms229005.aspx
Using the FacebookAuthenticationResult you can check if there was an error and then avoid to do the request:
private void FacebookLoginBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
FacebookAuthenticationResult authResult;
if (FacebookAuthenticationResult.TryParse(e.Uri, out authResult))
{
if (authResult.ErrorReason == "user_denied")
{
// Do something knowing that this failed (cancel). }
else
{
fbApp.Session = authResult.ToSession();
loginSucceeded();
}
}
}
Have you seen this post? http://dotnetslackers.com/articles/net/wFace-windows-phone-7-facebook-integration-part-1.aspx
Specifically, take a look at part 3 - http://dotnetslackers.com/articles/net/wp7Gesicht-windows-phone-7-facebook-integration-part-3.aspx
Could you store the access token, and then on error, show the login page again?

Categories

Resources