I tried to put the code as MVC c# form from console.
I want to show key with account, meter numbers, but I have no idea what I'm wrong.
What I want to try is that prints out all info in Details page.
Here is controller
public ActionResult Index()
{
return View(db.fedex.ToList());
}
private static RateRequest CreateRateRequest()
{
FedexModel fedex = new FedexModel();
// Build a RateRequest
RateRequest request = new RateRequest();
//
request.WebAuthenticationDetail = new WebAuthenticationDetail();
request.WebAuthenticationDetail.UserCredential = new WebAuthenticationCredential();
request.WebAuthenticationDetail.UserCredential.Key = fedex.AccessKey; // Replace "XXX" with the Key
request.WebAuthenticationDetail.UserCredential.Password = fedex.Password; // Replace "XXX" with the Password
//
request.ClientDetail = new ClientDetail();
request.ClientDetail.AccountNumber = fedex.AccountNumber; // Replace "XXX" with the client's account number
request.ClientDetail.MeterNumber = fedex.MeterNumber; // Replace "XXX" with the client's meter number
//
request.TransactionDetail = new TransactionDetail();
request.TransactionDetail.CustomerTransactionId = "***Rate v14 Request using VC#***"; // This is a reference field for the customer. Any value can be used and will be provided in the response.
//
request.Version = new VersionId();
//
request.ReturnTransitAndCommit = true;
request.ReturnTransitAndCommitSpecified = true;
//
//SetShipmentDetails(request);
//
return request;
}
//
// GET: /Fedex/Details/5
public ActionResult Details(int id = 0)
{
var request = CreateRateRequest();
return View(request);
}
If I click the key then it goes to next in Details page.
Details View
#model FedExShipping.Models.FedexModel
#using FedExShipping.WebReference;
#using FedExShipping.Controllers;
<h2>Details</h2>
<fieldset>
<legend>FedexModel</legend>
<div>
#Html.DisplayFor(model => model.AccessKey)
</div>
<div>
#Html.DisplayFor(model => model.Password)
</div>
<div>
#Html.DisplayFor(model => model.AccountNumber)
</div>
<div>
#Html.DisplayFor(model => model.MeterNumber)
</div>
What do I need to change for correct output?
Your action is returning View(request) so your model is being set to RateRequest. Which means your view for this action is interacting with RateRequest, not FedexModel. You can interact with anything that's set on your instance of RateRequest only. If you need something else, you need to change the model for the view and pass something other than an instance of RateRequest to it.
Related
I'm Trying To Have A button that create Data in a csv file and download it.
There are 2 options(That i know of)
I tried to Call the Action in the controller from Ajax.
But it doesn't work For me,. (all the code is in my pervious post:Sending string in controller to Ajax in View)
it does not generate the file.
So, i'm using a submit button that calls the action, and it works, but in this case
i need to be able to show a message to the user if the action did not generate the CSV file.
Any ideas how it can be done?
The Call to The action From the view:
#using (Html.BeginForm("Export", "Index", FormMethod.Post))
{
<input type="submit" id="btnSubmit" value="Export" />
}
Controller:
[HttpPost]
public FileResult Export()
{
var orderList = _unitOfWork.Order.GetAll().Where(a => a.OrderStatus == SD.OrderStatusAccepted).OrderBy(a => a.Id);
if (orderList.Count() == 0)
{
//Show message to the user that csv was not created
}
StringBuilder sb = new StringBuilder();
//
// generate data in string builder
//
return File(Encoding.ASCII.GetBytes(sb.ToString()), "text/csv", fileName);
}
When trying to return Back to view :
return View("Index");
I need to send a model with it
can i send it when returning to the view?
here is how i call my Index page:
public IActionResult Index()
{
var orderList = _unitOfWork.Order.GetAll();
dynamic myModel = new System.Dynamic.ExpandoObject();
myModel.Order = _unitOfWork.Order.GetAll();
myModel.ordercsv = new List<KTSite.Areas.Warehouse.Views.OrderWarehouse.CSVOrderLine>();
ViewBag.getProductName =
new Func<int, string>(returnProductName);
ViewBag.getStoreName =
new Func<int, string>(returnStoreName);
ViewBag.getCost =
new Func<int, double, double>(returnCost);
ViewBag.errSaveInProgress = false;
ViewBag.ExistInProgress = false;
return View(myModel);
}
According to your requirement, I suggest you could use iactionresult instead of fileresut and set a viewbig to store the error message.
More details, you could refer to below example:
[HttpPost]
public IActionResult Export()
{
// modify the if condition according to your requirement
if (true)
{
ViewBag.ErrorMessage = "File not generated";
return View("Index");
}
else
{
StringBuilder sb = new StringBuilder();
sb.Append("aaaaaaaaaaaaaaaaaaaaaaaa");
//
// generate data in string builder
//
return File(Encoding.ASCII.GetBytes(sb.ToString()), "text/csv", "aaaaaa");
}
//var orderList = _unitOfWork.Order.GetAll().Where(a => a.OrderStatus == SD.OrderStatusAccepted).OrderBy(a => a.Id);
//if (orderList.Count() == 0)
//{
// //Show message to the user that csv was not created
//}
}
View:
#using (Html.BeginForm("Export", "Home", FormMethod.Post))
{
<input type="submit" id="btnSubmit" value="Export" />
}
#if (ViewBag.ErrorMessage != null)
{
#section Scripts{
<script>
$(document).ready(function () {
alert("#ViewBag.ErrorMessage");
});
</script>
}
}
Result:
I am creating a feature in my app to process an uploaded CSV file containing multiple records to be imported. Data needs to be validated, and I want to show any validation errors BEFORE the Import button is clicked. High-level plan:
Step 1: Upload CSV file
Step 2: Display all records from CSV file and any validation errors next to each record (missing required fields, etc.)
Step 3: Click "Import" in order to actually import the valid records.
Here's a simplified version of what I have:
User View Model
public class UserViewModel
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(150)]
public string Email { get; set; }
[Required]
[StringLength(10)]
public string Phone { get; set; }
}
File Upload Action Post
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
// var csvRecords = do stuff to retrieve data from CSV file
var newUsersToCreate = new List<UserViewModel>();
foreach (var csvRecord in csvRecords)
{
newUsersToCreate.Add(new UserViewModel
{
Name = csvRecord.Name,
Email = csvRecord.Email,
Phone = csvRecord.Phone
});
}
return View("ImportPreview", newUsersToCreate);
}
View ImportPreview.cshtml
#model IEnumerable<App.ViewModels.UserViewModel>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "alert alert-danger", role = "alert" })
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Validation Errors</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(model => model)
</tbody>
</table>
<button type="submit">Import</button>
}
Editor Template for UserViewModel.cshtml
#model App.ViewModels.UserViewModel
<tr>
<td>
#Html.HiddenFor(model => model.Name)
#Html.DisplayFor(model => model.Name)
</td>
<td>
#Html.HiddenFor(model => model.Email)
#Html.DisplayFor(model => model.Email)
</td>
<td>
#Html.HiddenFor(model => model.Phone)
#Html.DisplayFor(model => model.Phone)
</td>
<td>
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</td>
</tr>
Problem
While this generates a nice "preview" table with all prepared User records as essentially rows of hidden fields ready to go, the problem is that it does not display validation errors until the Import button is clicked.
How can I get it to show per-field validation errors in each row, right after the return View('ImportPreview', newUsersToCreate) comes back with the view?
You could do this in the view by checking if the $.validator is valid. Since hidden inputs are not validated by default, you also need to override the validator. Add the following after the jquery-{version}.js, jquery.validate.js and jquery.validate.unobtrusive.js scripts (but not in $(document).ready())
<script>
// override validator to include hidden inputs
$.validator.setDefaults({
ignore: []
});
// validate form and display errors
$('form').valid();
</script>
Note that you might include a (say) <p id="error" style="display:none;"> tag containing a 'general' error message that the data is invalid and use
if ($('form').valid()) {
$('#error').show();
}
The disadvantage is that you need to include the jQuery scripts that otherwise are not needed.
Another option is to validate in the controller using TryValidateObject on each item in the collection, and add any errors to ModelState which will be displayed in your ValidationMessageFor() placeholders. Note the following assumes csvRecords implements IList<T> so that you can use a for loop.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
// var csvRecords = do stuff to retrieve data from CSV file
var newUsersToCreate = new List<UserViewModel>();
for (int i = 0; i < csvRecords.Count; i++)
{
UserViewModel model = new UserViewModel
{
Name = csvRecords[i].Name,
....
};
newUsersToCreate.Add(model);
// validate the model and include the collection indexer
bool isValid = ValidateModel(model, i));
}
return View("ImportPreview", newUsersToCreate);
}
private bool ValidateModel(object model, int index)
{
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(model);
if (!Validator.TryValidateObject(model, context, validationResults, true))
{
foreach (var error in validationResults)
{
string propertyName = $"[{index}].{error.MemberNames.First()}";
ModelState.AddModelError(propertyName, error.ErrorMessage);
}
return false;
}
return true;
}
The advantage of the controller code is that you could add an additional property to your view model (say bool IsValid) and use it for conditional styling of your table rows, and that you could decide that if there are 'too many' errors, you could just display a different view rather that rendering the whole table and displaying potentially hundreds of repeated error messages
I have a typical Create Action that was generated by scaffolding in MVC 4. Nothing fancy.
Normally I get to this page by the following URL /RecipeLines/Create and when I create that specific record I have a dropdown list I have altered to receive recipeID if sent:
<div class="editor-label">
#Html.LabelFor(model => model.RecipeID, "Recipe")
</div>
<div class="editor-field">
#Html.DropDownList("RecipeID", (SelectList)ViewBag.RecipeID, string.Empty)
#Html.ValidationMessageFor(model => model.RecipeID)
</div>
What I would like to do is link to the Create page by passing a recipeID, that would look something like this:
/RecipeLines/Create/2
I have edited the #Html.DropDownList to either accept a parameter and HOPEFULLY select the proper RecipeID or if it is linked to without the query string
/RecipeLines/Create
then it would not have a selected value.
Here is my Create Action as is.
// GET: /RecipeLines/Create
public ActionResult Create(int? recipeID)
{
ViewBag.MeasurementID = new SelectList(db.Measurements, "MeasurementID", "MeasurementEn");
ViewBag.RecipeID = new SelectList(db.Recipes, "RecipeID", "RecipeNameEn", recipeID);
ViewBag.IngredientID = new SelectList(db.Ingredients, "IngredientID", "IngredientNameEn");
return View();
}
My 2 #Html.ActionLink(s) looks like this:
//Coming from the Recipe Page
#Html.ActionLink("+", "Create", "RecipeLines", new { recipeID = recipe.RecipeID }, null);
//Coming from the RecipeLines/Index page
#Html.ActionLink("Create New", "Create")
THIS PROBLEM HAS BEEN SOLVED AND THE ABOVE CODE NOW WORKS
Try below code:
Create Action
public ActionResult Create(int? recipeId)
{
ViewBag.RecipeID = new SelectList(db.Recipes, "RecipeID", "RecipeNameEn",recipeId);
//
return View();
}
View
#Html.DropDownList("RecipeID", (SelectList)ViewBag.RecipeID,string.Empty)
ActionLink
#Html.ActionLink("+", "Create", "RecipeLines", new { recipeId= recipe.RecipeID }, null);
#Html.ActionLink("Create New", "Create")
I am using c# and ASP.NET MVC4 for a web application (with mobile template).
I'm having a problem with my Details view page. (First you select something from Index page and then it goes to Details page) I have put a bing map on the page and the map doesn't load.
First I thought it was something wrong with the map but its not.
I noticed that the url is
http://localhost:2550/Place/Details
of the page. However if I manually put a '1' on the end like so http://localhost:2550/Place/Details/1
then the map loads on the page. I don't understand why this is...
does anyone know why? thanks
my view page for Details:
#model Project.Models.Place
#{ ViewBag.Title = "Details";}
<h2>Place Details</h2>
<fieldset>
<div class="display-label"> Name: #Model.Name</div>
<div class="display-label">Address: #Model.Address</div>
<div class="display-label">Post Code: #Model.PostCode</div>
<div class="display-label"> PhoneNo: #Model.PhoneNo</div>
</fieldset>
<p> #Html.ActionLink("Back to List", "Index")</p>
<body onload="getMap();">
<div id='myMap' style="position:relative; width:400px; height:400px;"></div>
<div>
<input type="button" value="createWalkingRoute" onclick="createDirections();" />
</div>
<div id='directionsItinerary'> </div>
</body>
#section scripts{
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map = null;
var directionsManager;
var directionsErrorEventObj;
var directionsUpdatedEventObj;
function getMap() {
map = new Microsoft.Maps.Map(document.getElementById('myMap'), { credentials: 'mykey' });
}
function createDirectionsManager() {
var displayMessage;
if (!directionsManager) {
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
displayMessage = 'Directions Module loaded\n';
displayMessage += 'Directions Manager loaded';
}
alert(displayMessage);
directionsManager.resetDirections();
directionsErrorEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', function (arg) { alert(arg.message) });
directionsUpdatedEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', function () { alert('Directions updated') });
}
function createWalkingRoute() {
if (!directionsManager) { createDirectionsManager(); }
directionsManager.resetDirections();
// Set Route Mode to walking
directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.walking });
var seattleWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: 'Seattle, WA' });
directionsManager.addWaypoint(seattleWaypoint);
var redmondWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: 'Redmond, WA', location: new Microsoft.Maps.Location(47.678561, -122.130993) });
directionsManager.addWaypoint(redmondWaypoint);
// Set the element in which the itinerary will be rendered
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('directionsItinerary') });
alert('Calculating directions...');
directionsManager.calculateDirections();
}
function createDirections() {
if (!directionsManager) {
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: createWalkingRoute });
}
else {
createWalkingRoute();
}
}
</script>
}
my controller action for Details:
public ViewResult Details(int id)
{
ViewBag.events = eventRepository.PlaceEvents(id);
return View(placeRepository.Find(id));
}
Possible cause, may be you haven't written Controller default controller with Zero arguments.
Or you haven't written controller with [HttpPost] attribute
Will be easy if you put code for the controller here.
If you say that the navigation with /1 at the end works but your current url is without the number, your url on the index page is wrong.
Your url is now something like
#Html.ActionLink("Details", "Place")
Change it to something like this:
#Html.ActionLink("Details", "Place", new { id = #Model.Id })
So the problem is that your id isn't given to your details action.
I have such an action method:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Search(String filter, String value, Int32? page) {
var set = new List<Employee>();
switch(filter) {
case "by-name": {
set = this.repository.Get(
e => (e.LastName + " " + e.FirstName + " " + e.MiddleName) == value
).ToList();
break;
}
case "by-empn": {
set = this.repository.Get(
e => e.EmployeeNumber == value
).ToList();
break;
}
default: return RedirectToAction("Search", "Employee");
}
ViewBag.SearchedEmployees = set.Count();
return View(set.ToPagedList(page ?? 1, PageSize));
}
Search view is like this:
#if(Model.Count > 0) {
foreach(var item in Model) {
Html.RenderPartial("Employee.Card", item);
}
#Html.PagedListPager(
Model,
page => Url.Action("Search", new { page = page }),
new PagedListRenderOptions {
LinkToFirstPageFormat = "<< Beginning",
LinkToPreviousPageFormat = "< Back",
LinkToNextPageFormat = "Forth >",
LinkToLastPageFormat = "End >>"
}
)
}
Search form is presented as a partial view:
#using(Html.BeginForm("Search", "Employee", FormMethod.Get, new { #class = "search-form" }))
{
<p>
#Html.TextBox("value")
</p>
<p>
#Html.RadioButton("filter", "by-name", true) By name <br/>
#Html.RadioButton("filter", "by-empn") By empn <br/>
</p>
<p>
<input type="image" src="#Url.Content("~/Content/Images/Search.png")" />
</p>
}
Problem: I have N page links. When I try to go to the second page I face an infinite loop of redirects. That's the way I implemented my action - default case is fired. So filter/value values are null on the second action call? Why?
How do I refactor my search action?
Also how should I configure route for such an action?
Thanks!
EDIT
So should route for the search action look like:
routes.MapRoute(
null,
"{controller}/{action}/Page{page}/filter{filter}/val{value}",
new { controller = "Employee", action = "Search" }
);
?
EDIT 2
So it is possible to write next:
page => Url.Action("Search", new { filter = ViewBag.SearchFilter, value = ViewBag.SearchValue, page = page }),
And inside a controller:
public ActionResult Search(String filter, String value, Int32? page) {
ViewBag.SearchFilter = filter;
ViewBag.SearchValue = value;
// ...
}
Is this right?
So filter/value values are null on the second action call? Why?
Because their corresponding input fields are inside a separate form and are never sent to the server.
You seem to be using some custom Html.PagedListPager helper (the code for which you haven't shown) but I guess that this helper generates the page links as anchors and it simply doesn't take into account any current query string or POSTed values when generating those links. So the href of your pagination link looks like this /SomeController/Search?page=5 instead of the correct one which would take into account those parameters which is /SomeController/Search?page=5&filter=somefilter&value=somevalue.
You can now easily understand why the filter and value parameters in your controller action are always null. It's because you never send them to the server when clicking on the pagination links.
So in order to resolve this issue you could modify this custom HTML helper that you are using to generate the pagination links to include those additional parameters. Or maybe the helper allows you to pass additional parameters? Check the documentation if this is some third party plugin that you are using.