How to use Controller.TryUpdateModel outside of the Controller context? - asp.net-mvc

is it possible to use Controller.TryUpdateModeloutside of the Controller context?
For Example suppose that I want to use Controller.TryUpdateModel method in class which does not belong to MyApp.Controllers so how that could be done?.
this is my code.
public ActionResult ValidateAndSignUp(company newCompany)
{
if (ModelState.IsValid)
{
newCompany.CDTO.File = Request.Files["Logo"];
if(new CompanyActions().AddCompany(newCompany))
{
ViewBag.message = newCompany.CDTO.Message;
return View(newCompany.CDTO.RedirectTo);
}
else
{
if (newCompany.CDTO.HasFileError)
{
ModelState.AddModelError("Logo", "Invalid File");
return View(newCompany.CDTO.RedirectTo, newCompany);
}
else
{
ViewBag.error = newCompany.CDTO.Error;
return View(newCompany.CDTO.RedirectTo);
}
}
}
else
{
newCompany.CDTO.Countries = new DropDownLists().GetAllCountries();
return View("signUp", newCompany);
}
}

Related

ModelState validation on RedirectToAction in MVC

I want to implement ModelState.AddModelError on RedirectToAction in MVC. Currently, I am not getting error message. Can anyone please help me?
if(ModelState.IsValid)
{
var HList = hDetails.HTrackerList().Where(x => x.AccId == user.AccountID && x.UserId == user.Id).Select(y=>y.HorseId).ToList();
var datainList = HList.Contains(model.HorseId);
if(!datainList)
{
hDetails.InsertHorse(model);
}
else
{
ModelState.AddModelError("datainList", "Horse is already exist. Do you want to update it?");
}
}
return RedirectToAction("Home");
In the View:
#Html.ValidationMessage("datainList")
In your ontroller class:
public class YourController : Controller
{
[HttpPost]
public ActionResult TestMethod()
{
if(ModelState.IsValid)
{
var HList = hDetails.HTrackerList().Where(x => x.AccId == user.AccountID && x.UserId == user.Id).Select(y=>y.HorseId).ToList();
var datainList = HList.Contains(model.HorseId);
if(!datainList)
{
hDetails.InsertHorse(model);
}
else
{
TempData["datainListError"] = "Horse is already exist. Do you want to update it?";
}
}
return RedirectToAction("Home");
}
}
Then in the Home Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
if(TempData.ContainsKey("datainListError"))
{
ViewBag.ErrorMessage = TempData["datainListError"].ToString();
}
return View();
}
}
Then in the Index View:
#if(ViewBag.ErrorMessage != null)
{
<div class="alert alert-danger">#ViewBag.ErrorMessage</div>
}

MVC5 routing Programming C#

public static CustomerInfo Customer
{
get
{
if (System.Web.HttpContext.Current.Session["CustomerData"] == null)
{
System.Web.HttpContext.Current.Response.Redirect("~/Account/Login");
return new CustomerInfo();
}
else
{
return (CustomerInfo)System.Web.HttpContext.Current.Session["CustomerData"];
}
}
set
{
System.Web.HttpContext.Current.Session["CustomerData"] = value;
}
}
Whenever HttpContext.Current.Session["CustomerData"] is null, instead of redirecting to Login view in Account controller it is giving exception.
You can use
Return RedirectToAction("Login", "Account");
to redirect to another controller and method
Try:
if (System.Web.HttpContext.Current.Session["CustomerData"] == null)
{
Session["CustomerLogin"] = "True";
return new CustomerInfo();
}
else
{
Session["CustomerLogin"] = "False";
return (CustomerInfo)System.Web.HttpContext.Current.Session["CustomerData"];
}
Then in your controller check:
if(Convert.ToString(Session["CustomerLogin"]) == "True"){
return RedirectToAction("Login", "Account");
}

what should a method return from service layer

I am just wondering about the way to validate my viewmodel.
A user can own only one team, so I have to check it somehow if he hasn't got one.
public ActionResult AddTeam(TeamCreatingViewModel teamToAdd)
{
if (ModelState.IsValid)
{
//check if the user has got a team
if (!TeamService.checkIfUserHasCreatedTeam(User.Identity.GetUserId()))
{
//if not then allow him to create one
if (!TeamService.addTeam(teamToAdd, User.Identity.GetUserId()))
{
ViewBag.Info = "Success";
return View("Info");
}
else
{
ViewBag.Info = "It was impossible to create a new team";
return View("Error");
}
}
else
{
ViewBag.info = "You have a team!";
return View("Error");
}
}
else
{
return View("TeamCreatingForm", teamToAdd);
}
}
Or would the solution below be better ?
public ActionResult AddTeam(TeamCreatingViewModel teamToAdd)
{
if (ModelState.IsValid)
{
if (!TeamService.addTeam(teamToAdd, User.Identity.GetUserId())) //<--- now it is checking and adding (if allowed)
{
ViewBag.Info = "Success";
return View("Info");
}
else
{
ViewBag.Info = "It was impossible to create a new team";
return View("Error");
}
}
else
{
return View("TeamCreatingForm", teamToAdd);
}
}
How can I report (from service layer) if an error has occured (and what kind of )? In the second case, users won’t know anything about what was done wrong.
And in the first case I have to get an entity object 2 times, what seems to be useless.
You can report errors from business layer by throw out param, for example
public bool AddItem(string name, out List<string> errors){...}// or just string with error

How to stop code execute on condition from another controller?

my code:
public class StateManagementController : Controller
{
public void OwnerTest()
{
if (Session["Owner"] == null)
{
Logowanie();
}
}
public ActionResult Logowanie()
{
return RedirectToAction("Log", "Owner");
}
}
public class AnimalController : StateManagementController
{
public ActionResult MyAnimals()
{
OwnerTest();
//some code here
return View(animals.ToList());
}
}
The problem is that even if the session is null and Redirect is reached it doesn't redirect me but it still goes to ,,some code" in MyAnimals action, how can I stop it in ActionResult Logowanie? i dont want to change code in MyAnimals, I want only to use function there without checking if it returns something.
You Logowanie Action may return an ActionResult but the OwnerTest method ignores the returned result. Try this:
public class StateManagementController : Controller
{
public ActionResult OwnerTest()
{
if (Session["Owner"] == null)
{
return Logowanie();
}
else
{
return null;
}
}
public ActionResult Logowanie()
{
return RedirectToAction("Log", "Owner");
}
public class AnimalController : StateManagementController
{
public ActionResult MyAnimals()
{
var temp = OwnerTest();
if (temp != null)
{
return temp;
}
else
{
//some code here
return View(animals.ToList());
}
}
}

asp.net mvc related, mainly a refactor question

can anyone think of a better way to do this?
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveAction()
{
NameValueDeserializer value = new NameValueDeserializer();
// selected messages
MemberMessageSaveAction[] messages = (MemberMessageSaveAction[])value.Deserialize(Request.Form, "value", typeof(MemberMessageSaveAction[]));
// selected action
MemberMessageAction action = (MemberMessageAction)Enum.Parse(typeof(MemberMessageAction), Request.Form["action"]);
// determine action
if (action != MemberMessageAction.MarkRead &&
action != MemberMessageAction.MarkUnRead &&
action != MemberMessageAction.Delete)
{
// selected action requires special processing
IList<MemberMessage> items = new List<MemberMessage>();
// add selected messages to list
for (int i = 0; i < messages.Length; i++)
{
foreach (int id in messages[i].Selected)
{
items.Add(MessageRepository.FetchByID(id));
}
}
// determine action further
if (action == MemberMessageAction.MoveToFolder)
{
// folders
IList<MemberMessageFolder> folders = FolderRepository.FetchAll(new MemberMessageFolderCriteria
{
MemberID = Identity.ID,
ExcludedFolder = Request.Form["folder"]
});
if (folders.Total > 0)
{
ViewData["messages"] = items;
ViewData["folders"] = folders;
return View("move");
}
return Url<MessageController>(c => c.Index("inbox", 1)).Redirect();
}
else if (action == MemberMessageAction.ExportXml)
{
return new MemberMessageDownload(Identity.ID, items, MemberMessageDownloadType.Xml);
}
else if (action == MemberMessageAction.ExportCsv)
{
return new MemberMessageDownload(Identity.ID, items, MemberMessageDownloadType.Csv);
}
else
{
return new MemberMessageDownload(Identity.ID, items, MemberMessageDownloadType.Text);
}
}
else if (action == MemberMessageAction.Delete)
{
for (int i = 0; i < messages.Length; i++)
{
foreach (int id in messages[i].Selected)
{
MemberMessage message = MessageRepository.FetchByID(id);
if (message.Sender.ID == Identity.ID || message.Receiver.ID == Identity.ID)
{
if (message.Sender.ID == Identity.ID)
{
message.SenderActive = false;
}
else
{
message.ReceiverActive = false;
}
message.Updated = DateTime.Now;
MessageRepository.Update(message);
if (message.SenderActive == false && message.ReceiverActive == false)
{
MessageRepository.Delete(message);
}
}
}
}
}
else
{
for (int i = 0; i < messages.Length; i++)
{
foreach (int id in messages[i].Selected)
{
MemberMessage message = MessageRepository.FetchByID(id);
if (message.Receiver.ID == Identity.ID)
{
if (action == MemberMessageAction.MarkRead)
{
message.ReceiverRead = true;
}
else
{
message.ReceiverRead = false;
}
message.Updated = DateTime.Now;
MessageRepository.Update(message);
}
}
}
}
return Url<MessageController>(c => c.Index("inbox", 1)).Redirect();
}
I think you can also leverage the mvc framework for most of your code. Correct me if I'm wrong because I'm gonna make a few assumptions about your classes because I can't deduct it from your post.
My assumptions:
Request.Form["action"] is a single value selectbox
Request.Form["value"] is a multy value selectbox
action is the kind of action you want to be taken on all the messages
message is the list of values that should go with the action
I would try to leverage the framework's functionality where possible
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveMemberAction(SelectList selectedMessages, MemberMessageAction actionType){
//Refactors mentioned by others
}
If you then give your inputs in your Html the correct name (in my example that would be selectedMessages and actionType) the first few rules become unnessecary.
If the default modelBinder cannot help you, you might want to consider putting the parsing logic in a custom modelbinder. You can search SO for posts about it.
As a side note: you might want to reconsider your variable namings. "action" might be confusing with MVC's action (like in ActionResult) and MemberMessageSaveAction might look like it's a value of MemberMessageAction enum. Just a thought.
The first step will be making different methods for each action.
Next is to remove the negative logic.
This results in something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveAction() {
// SNIP
if (action == MemberMessageAction.Delete) {
return DoDeleteAction(...);
}
else if (action == MemberMessageAction.MoveToFolder) {
return DoMoveToFolderAction(...);
}
else if (action == MemberMessageAction.ExportXml) {
return DoExportXmlAction(...);
}
else if (action == MemberMessageAction.ExportCsv) {
return DoExportCsvAction(...);
}
else {
return HandleUnknownAction(...);
}
}
Turn MemberMessageAction into a class that has a Perform virtual function.
For your Special actions, group the common Perform code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveAction()
{
NameValueDeserializer value = new NameValueDeserializer();
MemberMessageSaveAction[] messages = (MemberMessageSaveAction[])value.Deserialize(Request.Form, "value", typeof(MemberMessageSaveAction[]));
MemberMessageAction action = MemberMessageAction.FromName(
messages,
Request.Form["action"]));
return action.Perform();
}
class MoveToFolder : SpecialAction { /*...*/ }
class ExportXml : SpecialAction { /*...*/ }
class ExportCsv : SpecialAction { /*...*/ }
class Delete : MemberMessageAction { /*...*/ }
class MarkRead : MemberMessageAction { /*...*/ }
class MarkUnRead : MemberMessageAction { /*...*/ }
abstract class MemberMessageAction {
protected MemberMessageSaveAction[] messages;
public MemberMessageAction(MemberMessageSaveAction[] ms) { messages = ms; }
public abstract ActionResult Perform();
public static MemberMessageAction FromName(MemberMessageSaveAction[] ms, string action) {
// stupid code
// return new Delete(ms);
}
}
abstract class SpecialAction : MemberMessageAction {
protected IList<MemberMessage> items;
public SpecialAction(MemberMessageSaveAction[] ms) : base(ms) {
// Build items
}
}
Now you can easily factor the code.
I don't like
MessageRepository.FetchByID(messages[i].ID)
this will make messages.Length (selected) queries to the database. I think you need to store your messages in ViewData, perform a filtering and pass them to Update() without the need to requery your database.
I came up with this.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update(MemberMessageUpdate[] messages, MemberMessage.Action action)
{
var actions = new List<MemberMessage.Action>
{
MemberMessage.Action.MoveToFolder,
MemberMessage.Action.ExportCsv,
MemberMessage.Action.ExportText,
MemberMessage.Action.ExportText
};
if (actions.Contains(action))
{
IList<MemberMessage> items = new List<MemberMessage>();
for (var i = 0; i < messages.Length; i++)
{
if (messages[i].Selected == false)
{
continue;
}
items.Add(MessageRepository.FetchByID(messages[i].ID));
}
if (action == MemberMessage.Action.MoveToFolder)
{
var data = new MessageMoveViewData
{
Messages = items
};
return View("move", data);
}
return new MessageDownloadResult(Identity.ID, items, action);
}
MessageRepository.Update(messages, action);
return Url<MessageController>(c => c.Index(null, null, null, null)).Redirect();
}

Resources