I've been reseraching dynamic CSS and the best solution I can find seems to be here on Stack Overflow, It's all looking good so far even though I made some changes but the one thing I can seem to figure out is what the View should be named and where I should place it.
I'm assuming that becasue it's a partial view it should be placed in Shared, but wanted to check that assumption. The controller the partial view code is located in is a Base Controller that all the other contollers then inherit (not sure if that makes a difference).
public class BaseController : Controller
{
public ActionResult CssDynamic()
{
Layout page = new Layout();
var dummyCorpId = 80;
page.Css = GetCss(dummyCorpId);
var model = page;
return new CssViewResult(model);
}
}
public class CssViewResult : PartialViewResult
{
private readonly object model;
public CssViewResult(object model)
{
this.model = model;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = "text/css";
base.ExecuteResult(context);
}
}
I've then added the action to the _Layout page, just not sure which View name to use or where to place it. Any help appriciated :)
Related
I am working on themes at present and the majority of work is going well am just at the phase where I am figuring out what view to present to the user.
This would be on a controller method so far I have.
public static class ThemeViewExtensions
{
public static string GetViewPath(RazorView view , string viewName = "Default")
{
var theme = "Default";
var themeViewPath = $"/Themes/{theme}{view.ViewPath}/{viewName}.cshtml";
return viewPath;
}
}
But for some reason I cannot access it here yes I have my using statement in
public IActionResult Index()
{
return View(this.GetViewPath());
}
What I want to happen is to be able to use it as above and be able to get the ViewPath and name that is being called for example /Controller/Action/ViewName whatever cshtml is that possible on a view?
I'm new to ASP.NET Core, so I'm still trying to understand it.
I was trying to access an object from code behind. Is it possible? I have been trying and searching for hours and I have yet to understand it. I'll leave some of what I've tried bellow, which apparently isn't working. If I could get some insight on this I'd very much appreciate it.
In classic ASP.NET I always to the id approach from code behind to the client side. But now I've been asked to try a different approach. In this case, a loop. How can I do this? I've also been reading the microsoft documentation but I still can't understand this. I'd appreciate some help.
Here's a spinnet of what I tried:
// The controller
public class HomeController : Controller
{
public GetInfo GetInfo { get; set; }
public IActionResult Offers()
{
GetInfo = new GetInfo();
GetInfo.GetOffers();
return View();
}
}
// The GetInfo class which gets data from a JSON file
public class GetInfo
{
public Offer.RootObject Offers { get; set; }
public void GetOffers()
{
var client = new RestClient("whatever.com");
// client.Authenticator = new HttpBasicAuthenticator(username, password);
var request = new RestRequest("Home/GetOffersJson", Method.GET);
IRestResponse response = client.Execute(request);
var content = response.Content;
var obj = JsonConvert.DeserializeObject<Offer.RootObject>(content);
Offers = new Offer.RootObject
{
total = obj.total,
data = obj.data
};
}
}
// The View file, where I'm trying to access the object from c#, which supposedly is 'loaded'
#model HostBookingEngine_HHS.Models.GetInfo;
#{
ViewData["Title"] = "Offers";
}
#foreach (var item in Model.Offers.data)
{
<span asp-validation-for="#item.TextTitle"></span>
}
Thanks, in advance.
asp.net core view has four over loading these are
public virtual ViewResult View();
public virtual ViewResult View(string viewName, object model);
public virtual ViewResult View(object model);
public virtual ViewResult View(string viewName);
ASP.NET Core can use all of these with exact parameter
You can pass your model object using Public Virtual ViewResult View(object model);
You need to pass your model object like this
return View(GetInfo);
which actually access your parameter object
#model HostBookingEngine_HHS.Models.GetInfo;
Also there are several method of passing data to view
Like ViewBag,ViewData which also grab the value in each request.
To have Offers available on view, you have to pass model to a view as an argument to View() method. So in your case you have to make your action look like:
public IActionResult Offers()
{
GetInfo = new GetInfo();
GetInfo.GetOffers();
return View(GetInfo);
}
I have such controller system in my project:
BaseController : Controller
AnyController : Controller
Code in my base Controller:
protected ViewResult View(string viewName, BaseViewModel model)
{
model.PromoBannerContent = _service.GetPromoBannerContent();
return base.View(viewName, model);
}
BaseViewModel - it's the layout model. And example of simple Action:
public virtual ActionResult UpdateAccount()
{
AccountViewModel account = _accountService.GetUser(Luxedecor.User.UserId).ToAccountViewModel();
return View(MVC.Account.Views.UpdateAccount, new
UpdateAccountViewModel()
{
AccountJson = JsonConvert.SerializeObject(account),
States = _accountService.GetStates(account.Country)
});
}
Where UpdateAccountViewModel : BaseViewModel.So my layout page is looking like that:
#model Luxedecor.ViewModel.BaseViewModel
#if (Model.PromoBannerContent != null)
{
...//Some html code
}
It's working fine, but I need to render the html promo banner not at all controller pages. I mean that I have for example AccountController: BaseController and I don't need this banner the AccountController Views. So I can create boolean property in my BaseViewModel and pass it from each Action in AccountController and other Contollers... But I wonder is exist more elegant solution for this issue? Could anyone experienced help me?
So, this is solution, what I've used for that:
public class RenderPromoBanner : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewBag.EnableBanner = true;
}
}
And then I've just used one if statement on the layout.
If you need to decide whether you need the banner or not on a per-Action basis (e.g. some actions in a controller need a banner whereas others in the same controller don't), the Action needs to communicate whether the banner is needed. Using a boolean is a viable option for this. Also, you could move the call to _service.GetPromoBanner into the Action and set the model property there if the banner is needed.
If all Actions in a controller need a banner or not, you could also create another subclass for the controllers that need a banner. This new subclass inherits from BaseController and contains the code to get the banner content. If a controller needs a banner, it derives from BannerController else from BaseController:
class BaseController : Controller
{
protected virtual ViewResult View(string viewName, BaseViewModel model)
{
return base.View(viewName, model);
}
}
class BannerController : BaseController
{
protected virtual ViewResult View(string viewName, BaseViewModel model)
{
model.PromoBannerContent = _service.GetPromoBannerContent();
return base.View(viewName, model);
}
}
I'm new to asp.net mvc (5) and I am facing an issue on my website.
Basically, all aspnet_users are linked to my specific user table via the guid.
I have a BaseController class with a UnitOfWork and a ViewModelBase :
public class BaseController : Controller
{
protected UnitOfWork UnitOfWork { get; private set; }
public ViewModelBase ViewModel { get; set; }
}
(Extract of) the ViewModelBase class, containing the information needed in the layout page :
public class ViewModelBase
{
public User User { get; set; }
public bool IsAuthentified { get; set; }
public bool Loaded { get; set; }
}
And the layout which uses it :
#model Project.ViewModels.ViewModelBase
<html>
<body>
Some very cool layout stuff related to the User in the ViewModelBase
</body>
</html>
Here is an example of use with the HomeController :
public class HomeController : BaseController
{
private new HomeViewModel ViewModel
{
get { return (HomeViewModel)base.ViewModel; }
}
public HomeController()
{
ViewModel = new HomeViewModel();
}
public ActionResult Index()
{
// I need to get the MembershipUser here to retrieve the related User and set it in the ViewModel
return View(ViewModel);
}
}
The HomeViewModel :
public class HomeViewModel : ViewModelBase
{
public string HomeSpecificProperty { get; set; }
}
And the view :
#model Project.ViewModels.HomeViewModel
#{
ViewBag.Title = "Home";
Layout = "~/Views/Shared/Layout.cshtml";
}
Welcome #Model.User.UserName !
<br />
#Model.HomeSpecificProperty
And here is my problem. The thing is all the pages have a viewmodel inherited from ViewModelBase, since it is used in the layout, but I don't know where nor how to set the User property in it.
Since Membership is used to retrieve the User it has to be in an Action, I can't do this in the ViewModelBase constructor.
Thus I added this code in the BaseController, which sets the ViewModelBase properties on the first get :
private ViewModelBase viewModel;
protected ViewModelBase ViewModel
{
get
{
if (!viewModel.Loaded)
LoadBaseContext();
return viewModel;
}
set { viewModel = value; }
}
private void LoadBaseContext()
{
viewModel.IsAuthentified = HttpContext.User.Identity.IsAuthenticated;
if (viewModel.IsAuthentified)
{
MembershipUser user = Membership.GetUser();
viewModel.Player = UnitOfWork.UserRepo.Get((Guid)user.ProviderUserKey);
}
viewModel.Loaded = true;
}
Might not be very beautiful, but works. However, since there is some database acesses in it (notably to get the User), I thought I should put the LoadBaseContext function async.
I tried, and since all actions use ViewModelBase I put every action async too. But then #Html.ActionLink doesn't work anymore since the action called is async.
Finally, my question is : Is this ViewModelBase and User property the right way to do ? If it is, should the LoadBaseContext be async ? Then, how to make it work with the actions ?
Thanks a lot.
UPDATE
Extract of the layout :
#if (!Model.IsAuthentified)
{
#Html.Action("Index", "Authentification", null) // display login partial view
}
else
{
#Html.Action("Index", "UserInfos", null) // display userinfos partial view
}
Authentification controller Index's action :
public ActionResult Index()
{
ViewModel = new AuthentificationViewModel();
// loads the ViewModelBase properties here
return PartialView("~/Views/Shared/Partials/Login.cshtml", ViewModel);
}
If you have something that you always want in all of your views, you could either ensure that every view takes a view model that includes or extends that core set of data, or you could simply put the data in the ViewBag.
To do the latter, you could override OnActionExecuting in your base controller, and set the ViewBag contents there.
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
this.ViewBag["IsAuthenticated"] = this.Request.IsAuthenticated;
// ...
}
If you want async behaviour, then you might be able to adapt this post to your needs.
To do this without overriding OnActionExecuting, you could put an async method in your controller base class that sets the data in the ViewBag:
protected async virtual Task PopulateViewBag()
{
this.ViewBag["foo"] = await MyAsyncMethod();
// ...
}
... and then simply call this from each and every one of your controller actions:
public async Task<ActionResult> MyAction()
{
await this.PopulateViewBag();
// ... more code
}
It would be a bit tedious, though.
One final word: depending on how many users you expect to have etc. it may be easier to get the user information once, and then cache it (e.g. in the Session), rather than repeatedly get it during every request. Presumably most of the user info isn't going to change between requests...
I set a Application variable in my global.asa.cs with:
protected void Application_Start()
{
...
// load all application settings
Application["LICENSE_NAME"] = "asdf";
}
and then try to access with my razor view like this:
#Application["LICENSE_NAME"]
and get this error:
Compiler Error Message: CS0103: The name 'Application' does not exist in the current context
what is the proper syntax?
Views are not supposed to pull data from somewhere. They are supposed to use data that was passed to them in form of a view model from the controller action. So if you need to use such data in a view the proper way to do it is to define a view model:
public class MyViewModel
{
public string LicenseName { get; set; }
}
have your controller action populate it from wherever it needs to populate it (for better separation of concerns you might use a repository):
public ActionResult Index()
{
var model = new MyViewModel
{
LicenseName = HttpContext.Application["LICENSE_NAME"] as string
};
return View(model);
}
and finally have your strongly typed view display this information to the user:
<div>#Model.LicenseName</div>
That's the correct MVC pattern and that's how it should be done.
Avoid views that pull data like pest, because today it's Application state, tomorrow it's a foreach loop, next week it's a LINQ query and in no time you end up writing SQL queries in your views.
#HttpContext.Current.Application["someindex"]
You can get the current Application using the automatically generated ApplicationInstance property:
#ApplicationInstance.Application["LICENSE_NAME"]
However, this logic does not belong in the view.
You should be able to access this via HttpContext.Current.Application[], however MVC best practices would state that you should probably consider passing this through your View Model.
Building on #Darin-Dimitrov pattern answered above, I passed a model into a partial view, which I loaded into a _Layout page.
I needed to load a web page from an external resource on Application Load, which will be used as the header navigation across multiple sites. This is in my Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Application["HeaderNav"] = GetHtmlPage("https://site.com/HeaderNav.html");
}
static string GetHtmlPage(string strURL)
{
string strResult;
var objRequest = HttpWebRequest.Create(strURL);
var objResponse = objRequest.GetResponse();
using (var sr = new StreamReader(objResponse.GetResponseStream()))
{
strResult = sr.ReadToEnd();
sr.Close();
}
return strResult;
}
Here is my controller Action for the partial view.
public class ProfileController : BaseController
{
public ActionResult HeaderNav()
{
var model = new Models.HeaderModel
{
NavigationHtml = HttpContext.Application["HeaderNav"] as string
};
return PartialView("_Header", model);
}
}
I loaded the partial view in the _Layout page like this.
<div id="header">
#{Html.RenderAction("HeaderNav", "Profile");}
</div>
The partial view _Header.cshtml is very simple and just loads the html from the application variable.
#model Models.HeaderModel
#MvcHtmlString.Create(Model.NavigationHtml)
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
var e = "Hello";
Application["value"] = e;
}
#HttpContext.Current.Application["value"]
I had this issue in an MVC controller and had to make fully qualified HttpContext for it to work ..
System.Web.HttpContext.Current.Application["VarName"]