my view have two dropdown and one submit buttom if no value is selected and if form get sumbited with GET method then my URL will be http://localhost:53372/question/index?Index=List&type=&stage=&mid=1&mod=5.
but i m applying an ActionFilter with OnActionExcuting() overriden method. so after submitting form URL is like http://localhost:53372/question/index?index=List&mid=1&mod=5.
where other two QueryString is gone?
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.QueryString["mid"] == null || filterContext.RequestContext.HttpContext.Request.QueryString["mod"] == null)
{
mid = Convert.ToString(HttpUtility.ParseQueryString(filterContext.RequestContext.HttpContext.Request.UrlReferrer.Query)["mid"]);
mod = Convert.ToString(HttpUtility.ParseQueryString(filterContext.RequestContext.HttpContext.Request.UrlReferrer.Query)["mod"]);
if (!string.IsNullOrEmpty(mid) || !string.IsNullOrEmpty(mod))
{
RouteValueDictionary redirecttargetDictionary = new RouteValueDictionary();
NameValueCollection Qstr = null;
if (filterContext.HttpContext.Request.RequestType == "GET")
{
Qstr = HttpUtility.ParseQueryString(filterContext.HttpContext.Request.Url.Query);
foreach (string item in Qstr)
{
redirecttargetDictionary.Add(item, Qstr[item]);
}
if (Qstr["mid"] == null)
{
redirecttargetDictionary.Add("mid", mid);
}
if (Qstr["mod"] == null)
{
redirecttargetDictionary.Add("mod", mod);
}
filterContext.Result = new RedirectToRouteResult(redirecttargetDictionary);
}
}
}
}
but if i select Dropdown value then all queryString is in URL.
QueryString with no values stage=&type= are not allowed?
By default MVC passes data as a query string unless you are submitting a form in which case the query string is bundled as part of the HttpRequest object. You can access the query string directly using the FormCollection object or as part of the HttpRequest object. The most direct way to access the query string is through the FormCollection object as follows
[HttpPost]
public ActionResult SubmitData(FormCollection form)
{
foreach(var key in form.AllKeys)
{
switch(key)
{
case "stage":
// do some work
break;
case "type":
// do some more work
break;
}
}
return RedirectToAction("SomeAction");
}
I have seen empty query string values cause issues with some browsers (I think IE) under certain circumstances. I suggest populating your DropDownList with a token instead of no value such as "Select..." and -1 for the value.
var dropDownList = new List<SelectListItem>();
dropDownList.Add(new SelectListItem{ Text = "Select", Value = "-1"} );
and then
#Html.DropDownList("stage", Model.Stages)
or something like that.
I hope this helps :)
Related
I have a page with many items on it. Each one has a button, that is supposed to take user to another jsp with another layout for detailed information about the current item. Can I even do this with ResponseEntity, as it doesn't redirect anywhere? Or may be there's some better way to do it and send my Object to the page? I tried "ResponseEntity.created(location).body(object)" but it doesn't do the job, I stay on the same page. May be I'm just using it wrong?
My method:
#RequestMapping(value = {"/details+{id}"}, method = RequestMethod.GET)
public ResponseEntity<Item> details(#PathVariable("id") int id) {
Item item = itemService.findById(id);
if(item == null){
return new ResponseEntity<Item>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<Item>(item, HttpStatus.OK);
}
Have a look at ModelAndView. It's purpose is to return a view with attached model to it. So for each value of the id, you can decide a pair of view and model to return.
#RequestMapping(value = {"/details+{id}"}, method = RequestMethod.GET)
public ModelAndView details(#PathVariable("id") int id) {
String viewToUse;
Map<String, Item> modelToUse;
if(id == ...) {
viewToUse = ...
modelToUse = ...
} else if (id == ...) {
viewToUse = ...
modelToUse = ...
} else if (id == ...) {
viewToUse = ...
modelToUse = ...
}
return new ModelAndView(viewToUse, modelToUse);
}
I have my basic Sitecore WebAPI route working just fine. But when I need to pass an array of integers to a custom Sitecore WebApi route, I get 404. How can this be done? Following is what I've tried and works perfectly fine in a typical WebApi route (without sitecore).
Route
AddWebApiRoute(
name: "StudentsCourseList",
routeTemplate: "api/v1/students/courselist",
defaults: new { controller = "StudentsApi", action = "GetCourses" });
Api Controller
public class StudentsApi: ApiController
{
public async Task<IHttpActionResult> GetCourses([ModelBinder(typeof(CommaDelimitedArrayModelBinder))]long[] courseids)
{
var result = await _client.GetCourses(courseids);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
}
Custom Model Binder
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var key = bindingContext.ModelName;
var val = bindingContext.ValueProvider.GetValue(key);
if (val != null)
{
var s = val.AttemptedValue;
if (s != null)
{
var elementType = bindingContext.ModelType.GetElementType();
var converter = TypeDescriptor.GetConverter(elementType);
var values = Array.ConvertAll(s.Split(new[] { ","},StringSplitOptions.RemoveEmptyEntries),
x => { return converter.ConvertFromString(x != null ? x.Trim() : x); });
var typedValues = Array.CreateInstance(elementType, values.Length);
values.CopyTo(typedValues, 0);
bindingContext.Model = typedValues;
}
else
{
// change this line to null if you prefer nulls to empty arrays
bindingContext.Model = Array.CreateInstance(bindingContext.ModelType.GetElementType(), 0);
}
return true;
}
return false;
}
And then trying to call as below, return a 404
/api/v1/students/courselist?courseids=1,2,3
Are there any missing parts that are needed to be done as part of Sitecore route setup?
To let Sitecore and WebApi work together in harmony you need to add a processor in the httpRequestBegin pipeline to get the routing to work. You can find information and even source code for this online, e.g. http://patrickdelancy.com/2013/08/sitecore-webapi-living-harmony
i want to add two queryString in current request URL if it is not exsist
Edited:
I tried this ---
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.QueryString["mid"] == null && filterContext.RequestContext.HttpContext.Request.QueryString["mod"] == null)
{
mid = Convert.ToString(HttpUtility.ParseQueryString(filterContext.RequestContext.HttpContext.Request.UrlReferrer.Query)["mid"]);
mod = Convert.ToString(HttpUtility.ParseQueryString(filterContext.RequestContext.HttpContext.Request.UrlReferrer.Query)["mod"]);
if (!string.IsNullOrEmpty(mid) || !string.IsNullOrEmpty(mod))
{
RouteValueDictionary redirecttargetDictionary = new RouteValueDictionary();
NameValueCollection Qstr = null;
if (filterContext.HttpContext.Request.RequestType == "GET")
{
Qstr = HttpUtility.ParseQueryString(filterContext.HttpContext.Request.Url.Query);
foreach (string item in Qstr)
{
redirecttargetDictionary.Add(item, Qstr[item]);
}
if (Qstr["mid"] == null)
{
redirecttargetDictionary.Add("mid", mid);
}
if (Qstr["mod"] == null)
{
redirecttargetDictionary.Add("mod", mod);
}
filterContext.Result = new RedirectToRouteResult(redirecttargetDictionary);
}
}
}
This code works fine.
-check for quesrystring exsist if no
-then take qstring value from 'Urlreferrer'
-if request type is GET
-then add two querystring with exsisting querystring
But but I having problem if querystring in current request has null value url like http://localhost:53372/question/index?type=&stage.if this ll b the current request url then code ll check for mid n mod qstring as its not exsist it will add both the qstring with exsisting type n stage but value ll b null then before hitting action again OnActionExecuting() get call this time first 'if' is not true and then index method get call but I m not getting type n stage querystring which suppose to null I found url in address bar is http://localhost:53372/question/index?mid=1&mod=5.
If I remove filter the I got URL http://localhost:53372/question/index?type=&stage=&mid=1&mod=5 here I m getting both stage n type querystring though its null.
Edited--
[HttpGet]
public ActionResult Index(ProjectType? projectType, int? projectStageID, int? page)
{
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
IPagedList<ProjectModule> moduleList = null;
IDictionary<string, string> queryParam = new Dictionary<string, string>();
queryParam["ProjectType"] = string.Empty;
queryParam["ProjectStageID"] = string.Empty;
ViewBag.ProjectType = null;
ViewBag.ProjectStage = null;
ViewBag.message = "";
if ((projectType != null || projectType.HasValue) && projectStageID.HasValue && page.HasValue)
{
queryParam["ProjectType"] = Request.QueryString["ProjectType"];
queryParam["ProjectStageID"] = Request.QueryString["ProjectStageID"];
//
//Set View Bag
//
ViewBag.ProjectType = Enum.Parse(typeof(ProjectType), Request.QueryString["ProjectType"]);
ViewBag.ProjectStage = Convert.ToInt32(Request.QueryString["ProjectStageID"]);
//
// Set Query String formcollection for Pagging purpose
//
ViewBag.QueryParam = queryParam;
moduleList = new ProjectModuleService().GetProjectModulesByProjectStageID(Convert.ToInt32(Request.QueryString["ProjectStageID"])).ToPagedList(currentPageIndex, Utility.ConstantHelper.AdminDefaultPageSize); ;
if (moduleList.Count == 0)
{
ViewBag.message = "Record(s) not found.";
}
return View(moduleList);
}
else
{
if (!string.IsNullOrEmpty(Request.QueryString["ProjectType"]) && !string.IsNullOrEmpty(Request.QueryString["ProjectStageID"]) && !string.Equals(Request.QueryString["ProjectStageID"], "0"))
{
if (!string.IsNullOrEmpty(Request.Params.Get("Index")))
{
queryParam["ProjectType"] = Request.QueryString["ProjectType"];
queryParam["ProjectStageID"] = Request.QueryString["ProjectStageID"];
//
//Set View Bag
//
ViewBag.ProjectType = Enum.Parse(typeof(ProjectType), Request.QueryString["ProjectType"]);
ViewBag.ProjectStage = Convert.ToInt32(Request.QueryString["ProjectStageID"]);
//
// Set Query String formcollection for Pagging purpose
//
ViewBag.QueryParam = queryParam;
moduleList = new ProjectModuleService().GetProjectModulesByProjectStageID(Convert.ToInt32(Request.QueryString["ProjectStageID"])).ToPagedList(currentPageIndex, Utility.ConstantHelper.AdminDefaultPageSize); ;
if (moduleList.Count == 0)
{
ViewBag.message = "Record(s) not found.";
}
return View(moduleList);
}
else if (!string.IsNullOrEmpty(Request.Params.Get("Create")))
{
return RedirectToAction("Create", new { projectStageID = Convert.ToInt32(Request.QueryString["ProjectStageID"]) });
//return RedirectToAction("Create", new { projectStageID = Convert.ToInt32(Request.QueryString["ProjectStageID"]), projectType = Enum.Parse(typeof(ProjectType), Request.QueryString["ProjectType"]) });
}
}
if (Request.QueryString["ProjectType"] == "" || Request.QueryString["ProjectStageID"] == "" || string.Equals(Request.QueryString["ProjectStageID"], "0"))
{
ViewBag.message = "Please select all fields.";
return View();
}
return View();
}
}
What I m doing wrong?
Here what I understand that if there are no querystring in the URL,you need to add two query string parameters. If you are adding this two querystring parameters explicitly than, it will be default value for that queryparameters.
It's better to provide default value in action method instead of adding queryparameters in URL. You can achieve by following code.
public ActionResult ComposeEmail(int queryParameter1 = 0,string queryParameter2 = string.Empty)
{
}
Do let me know, if you have any query.
How can i cache my items and values for dropdown list in MVC?
Is there a way to do so?
I am doing that in controller.
Sample code is.......
public ActionResult Index()
{
RegionTasks regionTasks = new RegionTasks();
ViewBag.Region = GetRegions();}
My controller has function as below.
[OutputCache(Duration = 10, Location = System.Web.UI.OutputCacheLocation.Server)]
private IEnumerable<SelectListItem> GetRegions()
{
RegionTasks regionTasks = new RegionTasks();
return regionTasks.GetRegions();
}
I have tested and it not caches the item for region.
How can i do that?
The OutputCache attribute is used on controller actions to cache the resulting output. It has strictly no effect on other methods.
If you want to cache custom objects you could use the HttpContext.Cache:
private IEnumerable<SelectListItem> GetRegions()
{
var regionTasks = HttpContext.Cache["regions"] as IEnumerable<SelectListItem>;
if (regionTasks == null)
{
// nothing in the cache => we perform some expensive query to
// fetch the result
regionTasks = new RegionTasks().GetRegions();
// and we cache it so that the next time we don't need to perform
// the query
HttpContext.Cache["regions"] = regionTasks;
}
return regionTasks;
}
The regionTasks are now cached under the regions key and accessible from anywhere in your ASP.NET application which has access to the HttpContext.Cache.
Darin is also right, how ever i have done following code to store on server for X minutes.
private IEnumerable<SelectListItem> GetGlobalUrlRegion(string profileName)
{
string cacheKey = "cacheUrlRegion";
RegionTasks regionTasks = RegionTasks.CreateRegionTasks();
IEnumerable<SelectListItem> regionUrlList = HttpContext.Cache[cacheKey] as IEnumerable<SelectListItem>;
if (regionUrlList == null)
{
var regionObject = regionTasks.GetRegions(profileName);
var cTime = DateTime.Now.AddMinutes(int.Parse(System.Configuration.ConfigurationSettings.AppSettings["GlobalCacheDurationInMin"].ToString()));
var cExp = System.Web.Caching.Cache.NoSlidingExpiration;
var cPri = System.Web.Caching.CacheItemPriority.Normal;
regionUrlList = regionObject;
HttpContext.Cache.Insert(cacheKey, regionObject, null, cTime, cExp, cPri, null);
}
return regionUrlList;
}
If I have the following code (EDIT: Sorry if I wasn't clear, I want to encapsulate the following (forget about the view its calling), so that I could do other stuff within the ActionResult):
public ActionResult ModelBased(string[] items, PostedItems postedItems) {
var model = new ItemsViewModel();
var selectedItems = new List<Item>();
var postedItemIDs = new string[0];
if (postedItems == null) postedItems = new PostedItems();
if (items!= null && items.Any()) {
postedCityIDs = items;
postedItems.ItemIDs = items;
}
if (postedItems.ItemIDs != null && postedItems.ItemIDs.Any()) {
postedItemIDs = postedIems.ItemIDs;
model.WasPosted = true;
}
if (postedItemIDs.Any())
selectedItems = ItemRepository.GetAll()
.Where(x => postedItemIDs.Any(s => x.Id.ToString().Equals(s))).ToList();
model.AvailableItems = ItemRepository.GetAll();
model.SelectedItems = selectedItems;
model.PostedItems = postedItems;
return View(model);
}
How might I reuse it in different Actions in my controller without having to copy/paste. I tried doing a private method with the code. But I am stuck on:
Either calling it wrong within an action method : private void Item (Item item) {//copied code from above} then calling Item(item); in the action; or
It has something to do with the (string[] items, PostedItems postedItems) that I am doing wrong; or
Something entirely different that I am not doing right.
Any examples would be much appreciated.
EDIT: The code above works with a CheckBoxList. It's one particular CheckBoxList. But I want to be able to use it in other views without having to copy/paste the code to other ActionResults. Just calling the ActionResult won't work, because I plan on doing other things. In particular, I have code for wizards in each ActionResult, such as:
if ((nextButton != null) && ModelState.IsValid)
return RedirectToAction("EMailConfirm");
return View("EMail/BasicDetails", myData);
which are returning specific views, so call to just the ActionResult won't work, unless I am missing something.
return View(model); tries to find a view for the original action.
Specify return View("ModelBased", model); to always render the view named "ModelBased"
public void SomeAction(string[] items, PostedItems postedItems)
{
// Modify the data as your like
return ModelBased(string[] items, PostedItems postedItems);
}
public void SomeOtherAction(string[] items, PostedItems postedItems)
{
// Modify the data as your like
return ModelBased(string[] items, PostedItems postedItems);
}
private ActionResult ModelBased(string[] items, PostedItems postedItems) {
var model = new ItemsViewModel();
var selectedItems = new List<Item>();
var postedItemIDs = new string[0];
if (postedItems == null) postedItems = new PostedItems();
if (items!= null && items.Any()) {
postedCityIDs = items;
postedItems.ItemIDs = items;
}
if (postedItems.ItemIDs != null && postedItems.ItemIDs.Any()) {
postedItemIDs = postedIems.ItemIDs;
model.WasPosted = true;
}
if (postedItemIDs.Any())
selectedItems = ItemRepository.GetAll()
.Where(x => postedItemIDs.Any(s => x.Id.ToString().Equals(s))).ToList();
model.AvailableItems = ItemRepository.GetAll();
model.SelectedItems = selectedItems;
model.PostedItems = postedItems;
return View(model);
}
Your example is unclear, however, I would normally move common functionality into a seperate method and mark it with [NonAction] attribute. E.g.
[NonAction]
protected UserInfo GetUserInfo(string username)
{
// Return relevant data
}
I would then call GetUserInfo in your action method.
Edit:
You need to look into partial views. You can think of a partial view as a control that you can re-use on multiple pages. For example, I can put a login control in a partial view and renged it on multiple pages. This will promote code re-usability.
I can't give you the example as I haven't done this for a while, but you'd have to do the following:
Instead of return View(); you'll have to return PartialView("_NameOfYourPartialView", viewModel);
Modify your view, so it's no longer a view, but a partial view.
You'll need to do a bit of reading and try it out for yourself.
Good luck
You can call this action from another action that returns ActionResult.
public ActionResult OtherAction()
{
return ModelBased(items, postedItems);
}
Also, why private void? Which part do you actually want to reuse? If it takes an Item and returns ItemsViewModel, it should be private ItemsViewModel - depends on the part you want to reuse. void doesn't return anything.