Site wide Tag Cloud - c#

I've created a tag cloud partial view for my site. The partialview is to be included on all pages on the site. The data comes from a database. Is there a way to run the code that lives in the controller globally, so I don't have to put it on every single action of every single controller?
I'd like to avoid putting this on every action:
public ActionResult Index()
{
ViewData["Tags"] = Tags.GetTags();
return View();
}
and
public ActionResult Index()
{
return View(Tags.GetTags());
}
It'd be a nightmare if I ever had to change that code. There has to be a better way of handling database bound content that is on every page of a site.

You could always use the ViewModel pattern and have a base ViewModel class for all your actions:
public abstract class ViewModelBase
{
public IEnumerable<Tag> Tags { get; private set; }
public ViewModelBase()
{
Tags = GetTagsFromDatabase();
}
}
Then just make every subsequent ViewModel inherit this base class.
public HomeViewModel : ViewModelBase
{
...
}
And then in your Controller action:
public ActionResult Index()
{
var viewModel = new HomeViewModel();
return View(viewModel);
}
Hope this helps.

You can put your global code either in your MasterPage, or you also make a custom control out of your code and reuse it in the pages that need that code.

Related

How to deal with two classes using methods from eachother?

I'm implementing MVC in C#, The controller has a property View to call its methods. My problem is that in the View when the user presses a button i want to notify the controller, in other words i need to access functions of the Controller class from my View. So i added a property Controller inside my View. Now this works, but it feels wrong and tight. What would be the way to go here ? Here's an example source code:
class Controller
{
public void DoSomething() { }
public void SetView (View v)
{
this.view = v;
}
private View view;
}
class View
{
public void SetController(Controller c)
{
this.controller = c;
}
public void OnButtonPress()
{
controller.DoSomething();
}
private Controller controller;
}
MVC is built the way it is so that the Controller, Model and View are separated and be easy to modify without one affecting the other
The controller should only have the actual logic while the View is only the presentation to the user
Try adding this to your View(html page):
#Html.ActionLink("linktext", "OnButtonPress", "ControllerName",new { #class = "yourButtonClass" })
Then add the method to your controller class with any logic you want:
class controller
{
public IActionResult OnButtonPress()
{
}
}

asp.net nested views with owns controllers

I have a target to create a nested architecture of view/controller. For example:
we have few areas in webpage. All this areas managed by its own controller. In another words I need to create independend pages and then join them in one page.
Please see the image:
So is it possible and where I can read about it? Thanks.
Yes you can achieve this by simply calling
#Html.Action("ActionName", "ControllerName");
Example:
in your case you can do like this
Controller1
public ActionResult View1()
{
return View("View1");
}
Controller2
public ActionResult View2()
{
return View("View2");
}
Controller3
public ActionResult View3()
{
return View("View3");
}
Calling in main page:
#Html.Action("View1", "Controller1");
#Html.Action("View2", "Controller2");
#Html.Action("View2", "Controller2");
call these in different section of main page wherever you want.
You can use #Html.Action() to render child views from different controllers
public class FirstController : Controller
{
public ActionResult Index()
{
return View();
}
}
public class SecondController : Controller
{
[ChildActionOnly]
public ActionResult Method1()
{
return PartialView();
}
}
public class ThirdController : Controller
{
[ChildActionOnly]
public ActionResult Method2(int ID)
{
return PartialView();
}
}
Index View (FirstController)
....
#Html.Action("Method1", "Second")
#Html.Action("Method2", "Third", new { ID = someValue })
You can also use #{ Html.RenderAction(); which is more efficient is you are generating a lot of html.

MVC Calling a view from a different controller

My project structure is like:
Controllers/ArticlesController.cs
Controllers/CommentsController.cs
Views/Articles/Read.aspx
Read.aspx takes a parameter say "output", which is the details of the article by id and its comments, passed from ArticlesController.cs
Now I want to write then read the comment:: write() & Read() funct in CommentsController.cs
For reading the article with its comments, I want to call Views/Articles/Read.aspx from CommentsController.cs by passing output parameter from CommentsController.cs
How can I do this?
UPDATE
Code Here:
public class CommentsController : AppController
{
public ActionResult write()
{
//some code
commentRepository.Add(comment);
commentRepository.Save();
//works fine till here, Data saved in db
return RedirectToAction("Read", new { article = comment.article_id });
}
public ActionResult Read(int article)
{
ArticleRepository ar = new ArticleRepository();
var output = ar.Find(article);
//Now I want to redirect to Articles/Read.aspx with output parameter.
return View("Articles/Read", new { article = comment.article_id });
}
}
public class ArticlesController : AppController
{
public ActionResult Read(int article)
{
var output = articleRepository.Find(article);
//This Displays article data in Articles/Read.aspx
return View(output);
}
}
To directly answer your question if you want to return a view that belongs to another controller you simply have to specify the name of the view and its folder name.
public class CommentsController : Controller
{
public ActionResult Index()
{
return View("../Articles/Index", model );
}
}
and
public class ArticlesController : Controller
{
public ActionResult Index()
{
return View();
}
}
Also, you're talking about using a read and write method from one controller in another. I think you should directly access those methods through a model rather than calling into another controller as the other controller probably returns html.
You can move you read.aspx view to Shared folder. It is standard way in such circumstances
I'm not really sure if I got your question right. Maybe something like
public class CommentsController : Controller
{
[HttpPost]
public ActionResult WriteComment(CommentModel comment)
{
// Do the basic model validation and other stuff
try
{
if (ModelState.IsValid )
{
// Insert the model to database like:
db.Comments.Add(comment);
db.SaveChanges();
// Pass the comment's article id to the read action
return RedirectToAction("Read", "Articles", new {id = comment.ArticleID});
}
}
catch ( Exception e )
{
throw e;
}
// Something went wrong
return View(comment);
}
}
public class ArticlesController : Controller
{
// id is the id of the article
public ActionResult Read(int id)
{
// Get the article from database by id
var model = db.Articles.Find(id);
// Return the view
return View(model);
}
}
It is explained pretty well here: Display a view from another controller in ASP.NET MVC
To quote #Womp:
By default, ASP.NET MVC checks first in \Views\[Controller_Dir]\,
but after that, if it doesn't find the view, it checks in \Views\Shared.
ASP MVC's idea is "convention over configuration" which means moving the view to the shared folder is the way to go in such cases.

How to transfer data between controllers in MVC 3?

I ve got 2 seperate controller sheets not just action methods..
MY First Controller:
namespace TestLokal.Controllers
{
public class BOUNCEController : Controller
{
BOUNCEDataDataContext db = new BOUNCEDataDataContext();
//
// GET: /BOUNCE/
[Authorize]
public ActionResult Index()
{
ViewData["Bouncers"] = new SelectList( db.Bouncers.Distinct(), "bouncer_id", "bouncer_name");
return View();
}
}
}
MY Second Controller:
namespace TestLokal.Controllers
{
public class DopplerController : Controller
{
//
// GET: /Doppler/
[Authorize]
public ActionResult Index()
{
elementmodel dop = new elementmodel();
ViewData["Dopplers"] = new SelectList( dop.BouncerList.Distinct(), "bouncer_id", "bouncer_name");
return View();
}
}
}
i wanna transfer data from first to second by using this model:
MY Model:
public class elementmodel
{
public IEnumerable<Bouncers> BouncerList { get; set; }
}
How can i achieve this?
You can use TempData for this.
See http://msdn.microsoft.com/en-us/library/dd394711(v=vs.90).aspx (passing data between action methods)
First of all ... are you sure you need two separate controller that has same data? In my humble opinion each controller should be responsible for handling his own group of models. If you need to have the same data in both of controllers maybe you should create some base class?
public class MyBaseController : Controller
{
//shared fields & methods for example datacontext
}
public class DopplerController : MyBaseController
{
}
public class BounceController : MyBaseController
{
}
but if I'm wrong and one of your controller just need results of work from another controller you can use Coockies, Session.
2 things come immediately to mind.
You can store the list of bouncers in the View as a JSON object
that gets POSTed off to the other controller.
You can use TempData to store it between requests. eg: http://msdn.microsoft.com/en-us/library/dd394711.aspx

Passing an optional object to all views

So, basically what I'd like is to do something like:
#if(Notification!=null){
//perform javascript notification with #Notification.Text
}
And I'd like to be able to do this on any view, so I will always have the option of specifying a notification object in my controller action, that, if defined, can be handled in the view.
My dream scenario is to allow this simply by creating the Notification object somehow, and then just returning the view. Meaning, I wouldn't need to explicitly pass the Notification object to the model. Like so:
public ActionResult MyAction(){
Notification n = new Notification("Text for javascript");
return View();
}
I'm thinking, that there might be a way to do this with some ViewPage-inheritance? But I'm really unsure of how to go about this?
In an ideal world, I would also love to be able to "override" what to do. For example, if I in my 'top'-layout choose to perform a certain kind of jquery-notification if the notification object exists, but maybe in some other nested view would like to handle it differently, I'd like the option to override the top-layouts handling of the object.
I know this last thing might be a little utopian (I'm just starting out with MVC and Razor), but it would be cool :)
You could write a custom global action filter which will inject this information on all views. For example:
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.Controller.ViewBag.Notification = new Notification("Text for javascript");
}
}
and then register this filter in the RegisterGlobalFilters method of your Global.asax:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new MyActionFilterAttribute());
}
And then in your views:
#if(ViewBag.Notification != null)
{
//perform javascript notification with #ViewBag.Notification.Text
}
Use ViewBag for simple stuff like popup message.
public ActionResult Index()
{
ViewBag.PopupMessage = "Hello!";
return View();
}
and then in view (or layout page)
#if (ViewBag.PopupMessage != null)
{
<div class="popup">#ViewBag.PopupMessage</div>
}
For more complicated stuff you will need to either create static class and save/read from HttpContext.Current.Items or override Controller and WebViewPage and save/read from ViewBag/ViewData.
Update:
public abstract class BaseController : Controller
{
public const string NotificationKey = "_notification";
protected string Notification
{
get
{
return ViewData[NotificationKey] as string;
}
set
{
ViewData[NotificationKey] = value;
}
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
protected string Notification
{
get
{
return ViewData[BaseController.NotificationKey] as string;
}
}
}
Views/Web.config
<pages pageBaseType="OverrideTest.Framework.BaseViewPage">
Usage:
public class HomeController : BaseController
{
public ActionResult Index()
{
Notification = "Hello from index!";
return View();
}
}
<div>Notification: #(Notification ?? "(null)")</div>
Or get test project here
Update 2:
Check out this blog post for another way to do something similar.

Categories

Resources