How "Don't Repeat Yourself" in methods of a Controller in ASP.NET MVC? - asp.net-mvc

within each methods of a controller , I have to execute a method.
public ActionResult Index1()
{
if (Foo(id, SessionManage.DataSession) )
return RedirectToAction("Page1");
Code4Index1();
return View();
}
public ActionResult Index2()
{
if (Foo(id, SessionManage.DataSession) )
return RedirectToAction("Page1");
Code4Index2();
return View();
}
public ActionResult Index3()
{
if (Foo(id, SessionManage.DataSession) )
return RedirectToAction("Page1");
Code4Index3();
return View();
}
public ActionResult Index4()
{
if (Foo(id, SessionManage.DataSession) )
return RedirectToAction("Page1");
Code4Index4();
return View();
}
Is there a smarter way than organize the code or I am forced to go against DRY concept?
I'd like not repeat the code for each method :
if (Foo(id, SessionManage.DataSession) )
return RedirectToAction("Page1");
Thanks to all.

Well, ASPNET has already the infrastructure for handling authorization so why not just use it?
Create a new attribute class, inherited from AuthorizeAttribute
Override the methods:
OnAuthorization: to perform your check
HandleUnauthorizedRequest: to decide whats the result view that the user will see.
Mark your controller methods with this attribute.
Your attribute may look like:
class MyCustomAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// Do whatever you want here, for example
//filterContext.Result = new whatever() ;
base.HandleUnauthorizedRequest(filterContext);
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if ( /* the request does not pass your checks */ )
throw new UnauthorizedAccessException();
}
}
And your controller code will look like:
[MyCustomAuthorize]
public ActionResult Index1()
{
return View();
}
[MyCustomAuthorize]
public ActionResult Index2()
{
return View();
}
[MyCustomAuthorize]
public ActionResult Index3()
{
return View();
}
[MyCustomAuthorize]
public ActionResult Index4()
{
return View();
}
You can also check this post for a more clear example:
https://stackoverflow.com/a/5663518/1413973

You can refactor your controller like this:
public ActionResult Index1()
{
return AccessDeniedRedirect();
}
public ActionResult Index2()
{
return AccessDeniedRedirect();
}
public ActionResult Index3()
{
return AccessDeniedRedirect();
}
public ActionResult Index4()
{
return AccessDeniedRedirect();
}
private ActionResult AccessDeniedRedirect()
{
if (Checks(id, SessionManage.DataSession))
return RedirectToAction("AccesDiened");
return View();
}

Related

Return Action as result of another action?

public ActionResult Index(int requestid)
{
return View(db.RequestListDetails.Where(c=>c.RequestID == requestid).ToList());
}
How can I back to View(db.RequestListDetails.Where(c=>c.RequestID == requestid).ToList()); from Create action.
My Create action code like this
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "....")] RequestListDetail requestListDetail)
{
if (ModelState.IsValid)
{
db.RequestListDetails.Add(requestListDetail);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(requestListDetail);
}
After db.SaveChanges() you could use this:
return RedirectToAction("Index", new { requestid = requestListDetail.RequestId });

Inconsistent accessibility: parameter type is less accessible

public class UserController : Controller
{
//
// GET: /User/
public ActionResult Register()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(User U)
{
if (ModelState.IsValid)
{
using (MyDatabaseEntities dc = new MyDatabaseEntities())
{
dc.Users.Add(U);
dc.SaveChanges();
ModelState.Clear();
U = null;
ViewBag.Message = "Successfully register Done";
}
}
return View(U);
}
}
I suspect, but without the full error message giving us the type and location in the code it is something of a guess, that type User is protected or internal.

Validation error about Decimal data type in asp.net mvc

I defined a data type decimal(18,10) for longitute and latitute in my database. But it always said "validation error" when I tried to input and submit my form.
I used LINQ to SQL. Is there some validation rules it generated for me otherwise why I can not input these two with something numbers like "2.34".
Thanks in advance
namespace Nerddinner.Models
{
interface IDinnerRepository
{
IQueryable<Dinner> FindAllDinners();
Dinner GetDinner(int id);
void AddDinner(Dinner dinner);
void UpdateDinner(Dinner dinner);
void DeleteDinner(Dinner dinner);
}
}
namespace Nerddinner.Models
{
public class sqlDinnerRepository: IDinnerRepository
{
dbDataContext db;
public sqlDinnerRepository()
{
db = new dbDataContext();
}
public IQueryable<Dinner> FindAllDinners()
{
return db.Dinners;
}
public Dinner GetDinner(int id)
{
return db.Dinners.SingleOrDefault(x => x.DinnerID == id);
}
public void AddDinner(Dinner dinner)
{
db.Dinners.InsertOnSubmit(dinner);
}
public void UpdateDinner(Dinner dinner)
{
db.SubmitChanges();
}
public void DeleteDinner(Dinner dinner)
{
db.Dinners.DeleteOnSubmit(dinner);
}
}
}
namespace Nerddinner.Controllers
{
public class DinnerController : Controller
{
IDinnerRepository _repository;
public DinnerController()
{
_repository = new sqlDinnerRepository();
}
public DinnerController(IDinnerRepository repository)
{
_repository = repository;
}
//
// GET: /Dinner/
public ActionResult Index()
{
var dinners = _repository.FindAllDinners();
return View(dinners);
}
//
// GET: /Dinner/Details/5
public ActionResult Details(int id)
{
var dinner = _repository.GetDinner(id);
return View(dinner);
}
//
// GET: /Dinner/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Dinner/Create
[HttpPost]
public ActionResult Create(Dinner dinner)
{
try
{
// TODO: Add insert logic here
_repository.AddDinner(dinner);
_repository.UpdateDinner(dinner);
return RedirectToAction("Index");
}
catch
{
return View(dinner);
}
}
//
// GET: /Dinner/Edit/5
public ActionResult Edit(int id)
{
var dinner = _repository.GetDinner(id);
return View(dinner);
}
//
// POST: /Dinner/Edit/5
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
var db = new dbDataContext();
var dinner = db.Dinners.SingleOrDefault(x => x.DinnerID == id);
try
{
// TODO: Add update logic here
UpdateModel(dinner, collection.ToValueProvider());
_repository.UpdateDinner(dinner);
return RedirectToAction("Index");
}
catch
{
return View(dinner);
}
}
//
// POST: /Dinner/Delete/5
[HttpPost]
public ActionResult Delete(int id)
{
var db = new dbDataContext();
var dinner = db.Dinners.SingleOrDefault(x => x.DinnerID == id);
try
{
// TODO: Add delete logic here
_repository.DeleteDinner(dinner);
_repository.UpdateDinner(dinner);
return RedirectToAction("Index");
}
catch
{
return View(dinner);
}
}
}
}
Thanks for helping me.
In ASP.NET MVC, You can use the DisplayFormatAttribute on your model property:
[DisplayFormat(DataFormatString = "{0:0.##}")]
public decimal decimalNumber { get; set; }
The above will output a number with up to 2 decimal places.
For more information visit: Custom Numeric Format Strings and Standard Numeric Format Strings
IN SQL SERVER:
*decimal(m,a)*: m is the number of total digits your decimal can have, while a is the max number of decimal points you can have.
so if you put PI into a Decimal(18,0) it will be recorded as 3
if you put PI into a decimal(18,2) it will be recorded as 3.14
if you put PI into Decimal(18,10) be recorded as 3.1415926535
I think my answer will help you. Correct me if I am wrong.

Is it possible to have both GET and POST asynchronous controller actions of the same name?

Is it possible to have an AsyncController that has a GET and POST action of the same name?
public class HomeController : AsyncController
{
[HttpGet]
public void IndexAsync()
{
// ...
}
[HttpGet]
public ActionResult IndexCompleted()
{
return View();
}
[HttpPost]
public void IndexAsync(int id)
{
// ...
}
[HttpPost]
public ActionResult IndexCompleted(int id)
{
return View();
}
}
When I tried this I got an error:
Lookup for method 'IndexCompleted' on controller type 'HomeController' failed because of an ambiguity between the following methods:
System.Web.Mvc.ActionResult IndexCompleted() on type Web.Controllers.HomeController
System.Web.Mvc.ActionResult IndexCompleted(System.Int32) on type Web.Controllers.HomeController
Is it possible to have them co-exist in any way or does every asynchronous action method have to be unique?
You can have the multiple IndexAsync methods, but only the one IndexCompleted method eg:
public class HomeController : AsyncController
{
[HttpGet]
public void IndexAsync()
{
AsyncManager.OutstandingOperations.Increment(1);
// ...
AsyncManager.Parameters["id"] = null;
AsyncManager.OutstandingOperations.Decrement();
// ...
}
[HttpPost]
public void IndexAsync(int id)
{
AsyncManager.OutstandingOperations.Increment(1);
// ...
AsyncManager.Parameters["id"] = id;
AsyncManager.OutstandingOperations.Decrement();
// ...
}
public ActionResult IndexCompleted(int? id)
{
return View();
}
}
(Only the attributes on the MethodNameAsync methods are used by MVC, so are not required on the MethodNameCompleted methods)

Is it possible to return anything else from controller apart from view?

Is it possible to return a string from controller upon a form submission ?
[HttpPost]
public ActionResult Index()
{
return Content("some string", "text/plain");
}
You can, as Darin suggest, return Content(string);
There are also other possibilities such as
[HttpPost]
public ActionResult Index(FormCollection form) {
/*
return Json(json);
return View;
return PartialView;
*/
}
If you return something other than an action result it will automatically be wrapped in a ContentResult.
[HttpPost]
public ContentResult Index(FormCollection form) {
/*
return Content(string);
return File(bytes, contentType);
return DateTime.Now;
return 2;
*/
}
public ActionResult Index()
{
// ...
return File(bytes, contentType);
}

Resources