Controller methods called twice? - asp.net-mvc

base controller:
public class AnaController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
ViewBag.AktifKullanici = kullaniciServis.AktifKullanici(KullaniciEposta);
base.OnActionExecuting(filterContext);
}
}
controller that is inherited from above controller:
public class AnasayfaController : AnaController
{
private HaberSitesiDbContext db;
private HaberServis haberServis;
private KullaniciServis kullaniciServis;
public AnasayfaController()
{
this.db = new HaberSitesiDbContext();
this.haberServis = new HaberServis(db);
this.kullaniciServis = new KullaniciServis(db);
}
// !!! following methods called twice !!!
public ActionResult Index()
{
return View();
}
public ActionResult _SolManset()
{
// id si 2 olanlar sol manset haberleri
var haberler = haberServis.PozisyonHaberler(2, 3)
.ToList();
return PartialView(haberler);
}
public ActionResult _Slider()
{
// id si 1 olanlar slider haberleri
var haberler = haberServis.PozisyonHaberler(1, 19)
.ToList();
return PartialView(haberler);
}
public ActionResult _Yazarlar()
{
var yazarlar = haberServis.KoseYazilari(5)
.ToList();
return PartialView(yazarlar);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
layout:
...
<article id="body">
#RenderBody()
</article>
...
Index:
<aside class="aside_small float_left">
#Html.Action("_SolManset", "Anasayfa")
</aside>
<section class="section_middle">
#Html.Action("_Slider", "Anasayfa")
</section>
<aside class="aside_small float_right">
#Html.Action("_Yazarlar", "Anasayfa")
</aside>
I cant find any solution. Any suggestion? There is no extra code, no js code. How can I find where second calling come from?

Related

HelpPage Dont find View after routing areas

I launched the API Help Page for the my web API project.
Now the question is that after Routing on other Areas my Help page can not be found index.cshtml. This is global.asax code and I posted a picture of the error message
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AreaRegistration.RegisterAllAreas();
MvcHandler.DisableMvcResponseHeader = true; /*Version Discloser 5 in 10 point*/
//Infrastructure.ConnectionStringEncryption.EncryptConnString();
//GlobalFilters.Filters.Add(new HandleAntiforgeryTokenErrorAttribute() { ExceptionType = typeof(HttpAntiForgeryException) });
}
My helppage controller code:
public class HelpController : Controller
{
private const string ErrorViewName = "Error";
public HelpController()
: this(GlobalConfiguration.Configuration)
{
}
public HelpController(HttpConfiguration config)
{
Configuration = config;
}
public HttpConfiguration Configuration { get; private set; }
public ActionResult Index()
{
ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
return View(Configuration.Services.GetApiExplorer().ApiDescriptions);
}
public ActionResult Api(string apiId)
{
if (!String.IsNullOrEmpty(apiId))
{
HelpPageApiModel apiModel = Configuration.GetHelpPageApiModel(apiId);
if (apiModel != null)
{
return View(apiModel);
}
}
return View(ErrorViewName);
}
public ActionResult ResourceModel(string modelName)
{
if (!String.IsNullOrEmpty(modelName))
{
ModelDescriptionGenerator modelDescriptionGenerator = Configuration.GetModelDescriptionGenerator();
ModelDescription modelDescription;
if (modelDescriptionGenerator.GeneratedModels.TryGetValue(modelName, out modelDescription))
{
return View(modelDescription);
}
}
return View(ErrorViewName);
}
}
And my help page view is here:

ViewContext.HttpContext.User.IsInRole("Admin") is not working

I am trying to hide a link or would not be able to go to the page if the user is not an administrator. I am able to do the latter using this code in my controller:
[AuthorizeRoles("Admin")]
public ActionResult Registration()
{
return View();
}
When I try to hide the link using this code:
#if (!Context.User.Identity.Name.IsEmpty())
{
<li id="dd_vehicle" class="dropdown">
VEHICLE <b class="caret"></b>
<ul class="dropdown-menu">
#if (ViewContext.HttpContext.User.IsInRole("Admin"))
{
<li id="item_registration">
#Html.ActionLink("Registration", "Registration", "Home")
</li>
}
}
The link gets hidden. But when I login as "Admin", still the link doesn't show.
This is how I AuthorizeAttribute:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
private readonly string[] userAssignedRoles;
public AuthorizeRolesAttribute(params string[] roles)
{
this.userAssignedRoles = roles;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorize = false;
using (var db = new SMBI_DBEntities())
{
var um = new UserManager();
foreach (var roles in userAssignedRoles)
{
authorize = um.IsUserInRole(httpContext.User.Identity.Name, roles);
if (authorize)
return authorize;
}
}
return authorize;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult("~/Home/UnAuthorized");
}
}
and this is in LoginView:
[HttpPost]
public ActionResult Login(UserLoginView ulv, string returnUrl)
{
if (ModelState.IsValid)
{
var um = new UserManager();
var password = um.GetUserPassword(ulv.LoginName);
if (string.IsNullOrEmpty(password))
{
ModelState.AddModelError("", "Login ID and Pasword do not match.");
}
else
{
if (ulv.Password.Equals(password))
{
FormsAuthentication.SetAuthCookie(ulv.LoginName, false);
return RedirectToAction("Registration", "Home");
}
else
{
ModelState.AddModelError("","Password provided is incorrect.");
}
}
}
return View(ulv);
}
Hope you could help. Thank you.
Hi You may try like the below:
#if(Page.User.IsInRole("Admin"))
{
<li id="item_registration">
#Html.ActionLink("Registration", "Registration", "Home")
</li>
}
Helpful link:How to use Page.User.IsInRole
And just as an additional info, you can also write helper like below for the future purpose if required
public static class PrincipalExtensions
{
public static bool IsInAllRoles(this IPrincipal principal, params string[] roles)
{
return roles.All(r => principal.IsInRole(r));
}
public static bool IsInAnyRoles(this IPrincipal principal, params string[] roles)
{
return roles.Any(r => principal.IsInRole(r));
}
}
Now simply you could call this extension method like this:
// user must be assign to all of the roles
if(User.IsInAllRoles("Admin","Manager","YetOtherRole"))
{
// do something
}
// one of the roles sufficient
if(User.IsInAnyRoles("Admin","Manager","YetOtherRole"))
{
// do something
}
Source: https://stackoverflow.com/a/32385065/3397630
Thanks

Unit testing logic in controller OnActionExecuting event

There is a custom logic to set the page title in my controller's OnActionExecuting event which sets default value for title if it is not set using an attribute on action methods:
[PageTitle("Overriden page title")]
public ActionResult About()
{
return View();
}
public ActionResult Error()
{
return View();
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Page title
var title = filterContext.ActionDescriptor.GetCustomAttributes(typeof(PageTitleAttribute), false);
if (title.Length == 1)
ViewBag.Title = ((PageTitleAttribute)(title[0])).Parameter;
else
ViewBag.Title = "Default Website Title";
}
How can I unit test this functionality?
This is what I ended up doing (might be helpful for anyone facing similar problem).
1) I split up the code in the controller to below:
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
SetupMetadata(filterContext);
base.OnActionExecuting(filterContext);
}
public virtual void SetupMetadata(ActionExecutingContext filterContext)
{
//Page title
var title = filterContext.ActionDescriptor.GetCustomAttributes(typeof(PageTitleAttribute), false);
if (title.Length == 1)
ViewBag.Title = ((PageTitleAttribute)(title[0])).Parameter;
else
ViewBag.Title = "Default Page Title";
}
}
2) Deriving my HomeController from the basecontroller.
3) And then unit tested it using:
[TestClass]
public class BaseControllerTests
{
[TestMethod]
public void OnActionExecuting_should_return_attribute_value_when_set()
{
var ctx = new Mock<ActionExecutingContext>();
var controller = new HomeController();
ctx.Setup(c => c.Controller).Returns(controller);
ctx.Setup(c => c.ActionDescriptor.GetCustomAttributes(typeof(PageTitleAttribute), false)).Returns(new object[] { new PageTitleAttribute("Overriden Title") });
controller.SetupMetadata(ctx.Object);
Assert.AreEqual("Overriden Title", controller.ViewBag.Title);
}
[TestMethod]
public void OnActionExecuting_should_return_default_attribute_values_if_attributes_are_missing()
{
var ctx = new Mock<ActionExecutingContext>();
var controller = new HomeController();
ctx.Setup(c => c.Controller).Returns(controller);
ctx.Setup(c => c.ActionDescriptor.GetCustomAttributes(typeof(PageTitleAttribute), false)).Returns(new object[0]);
controller.SetupMetadata(ctx.Object);
Assert.AreEqual("Default Page Title", controller.ViewBag.Title);
}
}

Can I no longer pass ViewData to _Layout.cshtml in MVC Core 1.0?

I'm trying to pass a URL for a background image to my _Layout.cshtml,
public HomeController()
{
this.ViewData["BackgroundImage"] = "1920w/Stipula_fountain_pen.jpg";
}
and
<body style="background-image: url(#(string.Format("assets/images/{0}", ViewData["BackgroundImage"])))">
...
</body>
but ViewData is always empty inside _Layout.cshtml. Is that working as intended? I'd rather not go down the BaseViewModel/BaseController route as that feels like overkill.
EDIT: It seems as if ViewData set in the constructor isn't actually used, because once an action is executing the collection is empty. If I set ViewData inside the action then that data is passed on to _Layout.cshtml - feels like a bug to me.
You can use an action filter to set ViewData for all controller actions:
public class SetBackgroundUrlAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var result = filterContext.Result as ViewResult;
if (result != null)
{
result.ViewData["BackgroundImage"] = "1920w/Stipula_fountain_pen.jpg";
}
}
}
[SetBackgroundUrl]
public HomeController()
{
}
Or just override OnActionExecuted method of the controller:
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
var result = context.Result as ViewResult;
if (result != null)
{
result.ViewData["BackgroundImage"] = "1920w/Stipula_fountain_pen.jpg";
}
}
Expanding on adem caglin's answer I went with this filter attribute, which can take an arbitrary URL:
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, AllowMultiple = false)]
public class SetBackgroundUrlAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
if (!string.IsNullOrWhiteSpace(this.Url))
{
var result = filterContext.Result as ViewResult;
if (result != null)
result.ViewData["BackgroundImage"] = this.Url;
}
}
public string Url { get; set; }
}
and is used like so:
[SetBackgroundUrl(Url = "1920w/Stipula_fountain_pen.jpg")]
public class HomeController : Controller
{
...
}

Refactoring a form in MVC2

I find myself pasting this code over and over on many views that deal with forms.
Is there a simple approach to refactor the following markup from a view in MVC2?
The only changing part is the route for the cancel link (LocalizedSaveButton and LocalizedCancelLink are helper methods I created).
I tried extracting it to a PartialView but I lose the BeginForm functionality. Any suggestions?
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<div class="span-14">
<% Html.EnableClientValidation(); %>
<%using (Html.BeginForm())
{%>
<fieldset>
<legend>Edit Profile</legend>
<%=Html.AntiForgeryToken() %>
<%=Html.EditorForModel() %>
<div class="span-6 prepend-3">
<%=Html.LocalizedSaveButton() %>
<%=Html.LocalizedCancelLink(RoutingHelper.HomeDefault()) %>
</div>
</fieldset>
<%}%>
</div>
You could wrap your code in an Html-Extension like the BeginForm. From your code call the BeginForm on the correct place.
You should return an object that implements IDisposable. In the dispose you call the Dispose of the stored result to BeginForm.
You end up with:
<% using (Html.MyBeginForm()) { %>
<%=Html.LocalizedSaveButton() %>
<%=Html.LocalizedCancelLink(RoutingHelper.HomeDefault()) %>
<% } %>
The trick is not to return a string or MvcHtmlString, but directly write the output using:
htmlHelper.ViewContext.Writer.Write(....);
It would do something like:
public class MyForm : IDisposable {
private MvcForm _form;
private ViewContext _ctx;
public MyForm(HtmlHelper html, /* other params */) {
_form = html.BeginForm();
_ctx = html.ViewContext;
}
public Dispose() {
_form.Dispose();
_ctx.Writer.Write("html part 3 => closing tags");
}
}
and the extension:
public static MyForm MyBeginForm(this HtmlHelper html /* other params */) {
html.ViewContext.Writer.Write("html part 1");
var result = new MyForm(html);
html.ViewContext.Writer.Write("html part 2");
return result;
}
Disclaimer: This is untested code.
Here is what I came up with:
It mostly works but I haven't been able to get the Html.EnableClientValidation() to cooperate with the rendered form.
namespace System.Web.Mvc
{
public class MyForm : IDisposable
{
private bool _disposed;
private readonly HttpResponseBase _httpResponse;
public MyForm(HttpResponseBase httpResponse)
{
if (httpResponse == null)
{
throw new ArgumentNullException("httpResponse");
}
_httpResponse = httpResponse;
}
public void Dispose()
{
Dispose(true /* disposing */);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
_httpResponse.Write("</form>");
}
}
public void EndForm()
{
Dispose(true);
}
}
}
public static class MyFormExtensions
{
public static MyForm FormHelper(
this HtmlHelper htmlHelper,
string formAction,
FormMethod method,
IDictionary<string, object> htmlAttributes,
string formLegendTitle)
{
TagBuilder tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttributes(htmlAttributes);
tagBuilder.MergeAttribute("action", formAction);
tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
return new MyForm(httpResponse);
}
public static MyForm MyBeginForm(this HtmlHelper html, string formLegendTitle) {
string formAction = html.ViewContext.HttpContext.Request.RawUrl;
var result = FormHelper(html,formAction, FormMethod.Post, null, formLegendTitle );
html.ViewContext.Writer.Write("<fieldset>");
html.ViewContext.Writer.Write(String.Format("<legend>{0}</legend>", formLegendTitle));
html.ViewContext.Writer.Write("<div class=\"span-14\">");
html.ViewContext.Writer.Write(html.AntiForgeryToken());
html.ViewContext.Writer.Write(html.EditorForModel());
html.ViewContext.Writer.Write("<div class=\"span-6 prepend-3 buttons\">");
html.ViewContext.Writer.Write(html.LocalizedSaveButton());
html.ViewContext.Writer.Write("</div>");
html.ViewContext.Writer.Write("</div>");
html.ViewContext.Writer.Write("</fieldset>");
return result;
}
public static void EndForm(this HtmlHelper htmlHelper)
{
HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
httpResponse.Write("</form>");
}
}

Resources