MVC + returning different PartialView on condition - c#

Not sure if this is the best approach in MVC but how do I return views on condition, let's say if I want to return another view which displays some error message if my 'fbUID' is missing, please kindly assist. Thanks.
public PartialViewResult GetCredentials(string facebookUID, string facebookAccessTok)
{
string fbUID = facebookUID;
if (fbUID != null)
{
// Request fb profile pic
var rawImg = new Bitmap(ImageHelper.requestBitmapImage(fbUID));
var processblurredImg = new Bitmap(rawImg);
var gb = new GaussianBlur();
for (int i = 0; i < 8; i++)
{
gb.ApplyInPlace(processblurredImg);
}
// Download it to local drive / server
string uploadPath = Server.MapPath("~/upload");
string fullPath = uploadPath + "\\ProfilePic.png";
if (!Directory.Exists(uploadPath))
{
Directory.CreateDirectory(uploadPath);
}
if (uploadPath != null)
{
ImageHelper.savePng(fullPath, processblurredImg, 500L);
}
return PartialView("BlurredPhoto");
}
return PartialView("TestPartialView"); //if fbUID is null
}

Have a look at action filters. These allow you to install a class via an attribute on your controller method which intercepts the call before your method runs. You can do this kind of basic checking here and return a standard error handler result from here.

ASP.NET MVC has a built-in HandleErrorFilterAttribute that helps you to return error views if some errors occured in action or other filters. The built-in HandleError filter returns view not a partial view so you may have to create a custom one to return a partial view. The idea is you have to throw some custom exception from your action if fbUID is null and the custom handle error filter returns a partial view if it handles that exception.
I suggest going for a custom handle error filter approach only if you see this functionality in many places else it's more work for a simple thing!

Related

Check if a model has data, within the view

QUESTION
How do I safely and efficiently check if a view model has been populated with data, within the view itself?
EXPLANATION
I'm passing in a model to a view like so;
return View(response.Success ? (SalesDashboardViewModel)response.Model : new SalesDashboardViewModel());
Now, the view either has a fully populated view model with all the data, or, if the view model wasn't populated correctly, it may have an empty 'SalesDashboardViewModel'. If the second case is true, when I call #Model.CountOfUsers in the view for example, I will get a null object reference error.
How, in the view, would I go about checking if this is empty or not, other than checking if one of it's properties is null (due to the fact the properties may change).
FULL CODE BREAKDOWN
// Controller
public ActionResult SalesDashboard(){
var response = DashboardService.BuildSalesViewModel(User.Identity.GetUserId());
return View(response.Success ? response.Model : new SalesDashboardViewModel());
}
// Populating the SalesDashboardViewModel
public CustomResponseModel BuildSalesViewModel(string userId)
{
try
{
CustomResponseModel response;
var vm = new SalesDashboardViewModel();
response = GetCountOfSuspectsAddedThisMonth(userId);
vm.NoSuspectsAddedThisMonth = response.Success ? (int)response.Model : throw new Exception(response.Reason);
response = GetCountOfProspectsAddedThisMonth(userId);
vm.NoPropectsAddedThisMonth = response.Success ? (int)response.Model : throw new Exception(response.Reason);
response = GetCountOfCustomersNotContactedRecently(userId, 12);
vm.NoCustomersNotContactedRecently = response.Success ? (int)response.Model : throw new Exception(response.Reason);
response = GetTopProspects(userId, 10);
vm.TopProspects = response.Success ? (List<Prospect>)response.Model : throw new Exception(response.Reason);
return new CustomResponseModel { Success = true, Model = vm };
}
catch (Exception e)
{
return new CustomResponseModel
{
Success = false,
Reason = e.Message,
};
}
}
If there is a better way of going about this then I'm open to suggestions. I appreciate the help :)
You can use Safe Navigation Operator (?.) to access the properties, if you are not sure that they will have the value.
#Model?.CountOfUsers
Find more details here.

Model Value is not setting

I am creating an CRUD Application in Asp.Net Core
After Add Operation I am redirecting to same view with setting model value as null to get another entry
Below is my code
public IActionResult Add(OptionMasterVM model)
{
try
{
model.QuestionList = context.QuestionMaster.Select(x => new SelectListItem { Text = x.QuestionName, Value = x.QuestionId.ToString() }).ToList();
if (HttpContext.Request.Method == "POST")
{
OptionMaster _optionmaster = new OptionMaster();
_optionmaster = model.OptionMaster;
using (var ctx = new QuestionnaireEntities(_configuration))
{
ctx.OptionMaster.Add(_optionmaster);
ctx.SaveChanges();
}
TempData["Msg"] = "Option Added Successfully , Add Another Option";
model.OptionMaster.OptionValue = string.Empty;
model.OptionMaster.OptionRating = 0;
return View(model);
}
}
catch (Exception ex)
{
logger.LogError(ex);
}
finally
{
}
return View(model);
}
Here I am setting Option Value to empty and rating to Zero to take next entry , but on view it does not show empty and zero , on view it show previously filled value.
After Setting below code these two fields should be reset but they don't
model.OptionMaster.OptionValue = string.Empty;
model.OptionMaster.OptionRating = 0;
Is there any other way to set model object as null in Asp.net Core ?
This can happen because Razor helpers use values from ModelState, rather than the model itself. Your OptionValue is probably displayed using a helper, for example:
#Html.TextBoxFor(m => m.OptionMaster.OptionValue)
When you change model values within an action, you need remove the old values from ModelState before rendering the View.
The easiest way of doing this is to call ModelState.Clear()
model.OptionMaster.OptionValue = string.Empty;
model.OptionMaster.OptionRating = 0;
ModelState.Clear(); // ensure these changes are rendered in the View
return View(model);
The values displayed for bound form fields come from ModelState, which is composed based on values from Request, ViewData/ViewBag, and finally Model. After posting, obviously, you'll have values set in Request, which will therefore be the values in ModelState. It works this way, so that when there's a validation error and the user is returned to the form to correct their mistakes, the values they posted will be there for them to edit.
Long and short, you need to follow the PRG (Post-Redirect-Get) pattern. Essentially, after posting, you only return the view on error. If the post is successful, you redirect. This not only clears ModelState, but also prevents accidental re-posts if the user attempts to refresh the page.
If you want to take the user back to the same view, simply redirect to the same action, but you need to do a redirect, not return the view.

Page redirect for incorrect Razor view loading

I am working on error handling and user experience for a single page application. I am using razor views and have everything hooked up, but want to account for any possibility. If the model that is passed to the view doesn't have an expected value, it throws a generic error. .
I would like to be able to reroute the page to a more friendly error page, with some detail about the issue, however I haven't been able to figure out a way to catch a bad model between it being sent to the view and the page attempting to load it.
My question is, is there a way to recognize when a razor view will throw this error before it happens? and if so, how can I intercept it and reroute to an error page?
As requested, Editing to show the controller object.
public ActionResult GetStoreRequests(string storeId, string storeName)
{
var requestListCustomRenderer = new RequestListCustomRenderer();
var storeRequestRenderedResult = new StoreRequestsRenderedResult();
var storeRequestResponse = _repository.GetStoreRequestInfo(storeId);
StoreRequestWithStoreName dto = _repository.GetStoreRequests(storeRequestResponse, storeId, storeName);
storeRequestRenderedResult.ChargeOffCount = dto.StoreRequestList.ChargeOffListRemovalList.Count();
storeRequestRenderedResult.ExtensionCount = dto.StoreRequestList.AgreementExtensionList.Count();
storeRequestRenderedResult.InventoryCount = dto.StoreRequestList.InventoryExchangeList.Count();
storeRequestRenderedResult.StoreId = dto.StoreId;
storeRequestRenderedResult.StoreName = dto.StoreName;
storeRequestRenderedResult.RenderedStoreRequests = requestListCustomRenderer.RenderStoreRequests(dto);
return PartialView("ApprovalView", storeRequestRenderedResult);
}
Don't you want just try/catch your PartialView?
Like this:
try
{
PartialViewResult res = PartialView("ApprovalView", storeRequestRenderedResult);
return res;
}
catch (Exception ex)
{
return RedirectToAction("Error", "Home");
}

MVC Response.Redirect not working

I have a method inside MVC Controller which is called from href inside anchor tag.
public ActionResult DoSomething(string value)
{
if(true)
{
return new RedirectResult("http://google.com");
}
}
when I debug and hit that method Response.Redirect does nothing no exceptions either. any ideas?
Thanks in advance!
Use Redirect
return Redirect("http://www.google.com");
Response.Redirect is not preferred way of doing redirects in asp.net mvc
Response.Redirect and ASP.NET MVC – Do Not Mix
Update: It seems that you are trying to redirect ajax request. If you redirect ajax request, your main page won't be redirected.
There are a few things you need to do here to avoid all these issues.
Starting with the AJAX errors you're getting, they most like relate to the javascript debugger, which Microsoft refer to as "BrowserLink".
If you use Firefox or Chrome, this feature simply doesn't work, which is probably the easiest way to avoid the issue, however you can disable the feature here:
You can change the default browser to run the website in just to the left.
In terms of Response.Redirect, I think that's been well covered, you should use return Redirect() instead, however your code needs to be refactored to allow for that.
Assuming that method is a helper method which is required to be separate from the controller itself, there are a couple of main approaches to doing what you're trying to to do.
1) Magic Values
This could include "redirect1" or also commonly null, and would look something like:
public ActionResult MyAction
{
string data = ProcessString("some data");
if (data == null) { return Redirect("google.com"); }
}
public string ProcessString(string input)
{
if (condition) { return null; }
string output = input + "!"; // or whatever you need to do!
return input;
}
2) Handle via exceptions
Assuming the problem is that the data is in some way bad, and you want to redirect away because you cant process it, Exception handling is most likely the way to go. It also allows for different types of exceptions to be raised by a single method and handled independently without having magic values which then can't be used as normal data.
public ActionResult MyAction
{
string data; // remember this will be null, not "" by default
try
{
data = ProcessString("some data");
}
catch (OwlMisalignedException ex)
{
return RedirectToAction("Index", "Error", new { exData = ex.Code });
}
// proceed with controller as normal
}
public string ProcessString(string input)
{
if (condition)
{
throw new OwlMisalignedException(1234);
// this is (obviously) a made up exception with a Code property
// as an example of passing the error code back up to an error
// handling page, for example.
}
string output = input + "!"; // or whatever you need to do!
return input;
}
By using that approach you can effectively add extra return states to methods without having to fiddle with your return type or create loads of magic values.
Don't use throw Exception - either use one of the more specific types ArgumentException and ArgumentNullException will probably come in handy, or create your own types if needs be.
You'll find info on creating your own Exception types on here easily enough.

One property with a list of model errors in mvc c#

In my controller which is having a list (atmost 3) error messages related to password check will be stored in the property named Password.
IEnumerable<PasswordMessages> passwordMessage = LoanTrackerServices.CheckPasswordRequirements(model.NewPassword, model.EmailId);
if ( passwordMessage.Count() > 0 )
{
foreach (PasswordMessages pm in passwordMessage)
{
ModelState.AddModelError("Password",( pm.Message));
}
LoginPageModel loginModel = new LoginPageModel();
return View("Index", new HomePageModel() { Register = model, Login = loginModel });
}
But in my view i am unable to figure out how to get all those (atmost 3) error messages. Right now only the first message with in the list is displaying. here is my code in view
for (int i = 0; i < ViewData.ModelState["Password"].Errors.Count; i++)
{
#Html.ValidationMessage("Password")
}
How to get all those error messages which are stored with in the Password?
You just need a summary instead of a message:
#Html.ValidationSummary("Password")
So get rid of this:
for (int i = 0; i < ViewData.ModelState["Password"].Errors.Count; i++)
{
#Html.ValidationMessage("Password")
}
#Html.ValidationSummary()
Will show all Model errors in one place what isn't desirable for the most cases.
I've written a helper method which will let you show only errors for specific field: https://gist.github.com/DimaSalakhov/8548393. It's based on standart ValidationMessageFor<>().
Add it to your project, referrence on a View and use as follows:
#Html.ValidationSummaryFor(x => x.Password)
#if(ViewData.ModelState.IsValidField(nameof(Model.Property)))
{
// show some thing
}
else
{
// show some thing else
}
Strongly typed validation check .

Categories