How to transfer data between controllers in MVC 3? - c#

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

Related

The controller for path ... was not found or does not implement IController

I am writing an application using ASP.NET MVC 5 using c#. I have a need to add a global menu on the upper right hand side of the application. I was advised other SO to use action with ChildActionOnly attribute.
So here is what I have done.
I created a BaseController like this
public class BaseController : Controller
{
[ChildActionOnly]
public ActionResult ClientsMenu()
{
using (SomeContext db = new SomeContext())
{
return PartialView(db.Database.SqlQuery<Client>("SELECT * FROM clients").ToList());
}
}
}
Then I inherited all my controllers from BaseController like so
public class TasksController : BaseController
{
public ActionResult Index(int ClientId)
{
...
return View();
}
public ActionResult Show(int SurveyId)
{
...
return View();
}
}
To render the ClientsMenu in my layout I added the following code
#Html.Action("ClientsMenu", "Menus")
Now when I run my application I get the following error
The controller for path '/Tasks/Index' was not found or does not implement IController.
When I remove #Html.Action("ClientsMenu", "Menus") from the layout everything works fine but the global menu does not show of course.
What can I do to resolve this issue?
Updated
Here is what I have done after the feedback I got from the comments below
public class TasksController : Controller
{
[ChildActionOnly]
public ActionResult ClientsMenu()
{
using (SomeContext db = new SomeContext())
{
return PartialView(db.Database.SqlQuery<Client>("SELECT * FROM clients").ToList());
}
}
public ActionResult Index(int ClientId)
{
...
return View();
}
public ActionResult Show(int SurveyId)
{
...
return View();
}
}
but still the same error
Take ClientMenus Action out of the BaseController and put it into its own controller MenusController. You can then call that controller from your Views.
#Html.Action("ClientsMenu", "Menus")
In your example you don't have a MenusContoller which is what #Html.Action("ClientsMenu", "Menus") is looking for.
The Phil Haacked - Html.RenderAction and Html.Action article linked to by the other post provided a good example for you to follow.

How To Set [Authorize] attribute to only a group of ActionResults Within The Controller

Suppose I have a Controller with 100's of ActionResult's Like Below
public class BasicController : Controller
{
public ActionResult Apple1()
{
}
public ActionResult Apple2()
{
}
.
.
.
public ActionResult Apple100()
{
}
public ActionResult Mango1()
{
}
public ActionResult Mango2()
{
}
.
.
.
public ActionResult Mango100()
{
}
}
Now How can I set [Authorize(Role="AppleAdmin")] to only Apple named methods and [Authorize(Role="MangoAdmin")] Mango named methods?
I know we can do it by decorating each ActionResult individually. But What I want to know is, Is there a way to set the Authorize to a Group of ActionResults once. So that makes me use the Authorize attribute only twice in my above scenario.
Assuming cleaning up the controller isn't an option, the only answer I can think of is a custom AuthorizeAttribute on the controller.
If you override the OnAuthorization method you can inspect the AuthorizationContext argument for the action name (filterContext.ActionDescriptor.ActionName) and set filterContext.Result = new HttpUnauthorizedResult if it fails your logic.
Something like
public class AppleMangoAuthorizeAttribute : AuthorizeAttibute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.ActionDescriptor.ActionName.Contains("Apple") /*&& some other failing logic*/)
{
filterContext.Result = new HttpUnauthorizedResult();
}
else if (/*same for mango*/)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
Then
[AppleMangoAttribute]
public class BasicController : Controller
{
public ActionResult Apple1()
{
}
}
I would separate the controller in 2 classes and just modify the routing to access the 2 controllers via the same route.
Note: Personally I haven't tested if this solution will crash the routing but it's the best I could come up with:
[Authorize(Role="AppleAdmin")]
[Route("BasicController")]
public class BasicControllerApple : Controller
{
public ActionResult Apple1()
{
}
}
[Authorize(Role="MangoAdmin")]
[Route("BasicController")]
public partial class BasicControllerMango : Controller
{
public ActionResult Mango1()
{
}
}

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.

Site wide Tag Cloud

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.

Categories

Resources