I'm trying to pass in values from a html file into a c# file using "get" as my method. my c# code currently looks like this:
namespace animals
{
internal class Program
{
static void Main(string[] args)
{
using (var client = new HttpClient())
{
var endpoint = new Uri("C:/localWebSite/cgi-zoo.html");
var result = client.GetAsync(endpoint).Result;
Console.WriteLine(result);
}
}
}
}
And my form submission line looks like this:
<form name="zooForm" action="C:\localWebSite\theZoo\animals.exe" method="get" onsubmit="return getAnimal();">
What I need to do is pass in 2 variables for use and it needs to be a string and an int, The c# code will then return the user to another page (from the c# code not another html) that displays a picture and some supporting text for the picture. From those data types the most important one is the int because I need to use it to determine what picture I am going to show back to the user and what text document I'm going to use to support that picture.
My problem is I'm having a hard time figuring out how exactly data gets passed from the html into the c# program and when it does eventually get passed how to separate it into the string and the integer.
Yeah, I think you need to be a little more specific. If I had to guess, you want this.
Html Page 1
#*some html*#
<form action="yourAction" method="get">
<input type="number" name="numBer" />
<input type="text" name="someString" />
<input type="submit" value="SUBMIT FORM" />
</form>
then the form will send to the action, here:
public IActionResult yourAction(string fooBar, int numBer)
{
//write in your logic here, like find the picture that matched 'numBer'
//then, when you are ready, do below. I included the parameter because
//you might need it
return RedirectToAction("theNextView", new { numBer = numBer });
}
which will send the user to the next view.
although, maybe i totally misread this question. but thats how I interpret what you are asking. also, you should probably 'post' the data to the action, not 'get'
I am creating an application that presents users with a form. When the user submits the form, my application takes those values and formats them into a query string. This string is then used to make a call to a third party API. The application is written in C# using an ASP.NET Core Razor Pages template in Visual Studio 2019. I had first experimented with creating an HTTPClient and sending an HTTPRequestMessage to the third party API using hard-coded values in a console app, which worked perfectly. However, when moving my code into a Razor Pages application to add a front end for the app I can't seem to get the application to call the code I created. Since I am only taking form values and passing them in a query string to a third-party API, which doesn't require me to define my own model, I decided to use Razor Pages instead of ASP.NET MVC.
This is the Index.cshtml page as I set it up in my application:
#page
#model IndexModel
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#{
ViewData["Title"] = "Home page";
}
<div>
<form asp-page-handler="ProcessRequest" method="post">
<label for="FirstName">First Name:</label>
<input type="text" name="FirstName" value="" />
<label for="LastName">Last Name:</label>
<input type="text" name="LastName" value="" />
<label for="Email">Email:</label>
<input type="text" name="Email" value="" />
<button type="submit">Send Request</button>
</form>
</div>
As you can see, it is just a simple form with three input fields, nothing fancy.
The underlying Index.cshtml.cs file containing the model logic has the following code:
public class IndexModel : PageModel
{
static HttpClient myAppHTTPClient = new HttpClient();
public async void OnPostProcessRequestAsync()
{
string firstName, lastName, email;
string host = "https://thirdparty.app.com:443/";
string pathname = "path/to/api/endpoint/?operation=create";
firstName = "Test";
LastName = "User";
email = "TestUser#email.com";
string path = pathname + "&first_name=" + firstName + "&last_name=" + lastName + "&email=" + email;
string requestUrl = host + path;
HttpRequestMessage httpRequestMessage = new HttpRequestMessage();
try
{
HttpResponseMessage responseMessage = await myAppHTTPClient.PostAsync(requestUrl, httpRequestMessage.Content);
HttpContent content = responseMessage.Content;
string message = await content.ReadAsStringAsync();
Console.WriteLine("The output from thirdparty is: {0}", message);
RedirectToPage();
}
catch (HttpRequestException exception)
{
Console.WriteLine("An HTTP request exception occurred. {0}", exception.Message);
}
}
}
The documentation for ASP.NET Razor Pages says that when you have an asp-page-handler tag helper in your form submitting the form will call the page handler method OnPost[method_name]Async(). In my case, the line <form asp-page-handler="ProcessRequest" method="post"> in the form should call the public async void OnPostProcessRequestAsync() method. However, this isn't working as I thought it would. I tried using different tag helpers in the form and in the submit button. Is there a way to get the Razor Page to call the method that runs my code. I know I am missing the RedirectToPage() method but I first want to get the method call to work.
Though two people on this thread already suggested the answer, I didn't see a way where I could mark their comments as having answered the question. So, to be fair and give credit where credit is due, their suggestions allowed me to fix my code. Basically, I had defined the page handler method incorrectly. I had defined it as:
public async void OnPostProcessRequestAsync()...
However, this type of application requires page handler methods to return something like Task. When changing the return type from void to Task this worked perfectly. My guess is that since I am defining this code asynchronously, the return value must be something asynchronous. Since the Task<> class is used for Threading (async) code it makes sense that this would work.
I am trying very hard to rewrite this question better than my previous effort which received no responses. Even though I’m nearly done with this application, I am still a relative newbie at programming and it seems like one challenge just leads to another. I have looked at many posts related to the problem of passing a parameter to several Partial Views in a single view page. So let’s take this in order from the AlertPick.cshtml page where the user chooses one of three Alert_Identifier/SelectedAlertIndex parameters from the application database. I’m only showing the #model and Select Tag Form.
#model edxl_cap_v1_2.Models.ContentViewModels.EdxlCapMessageViewModel
#{
<h4>#Model.Alerts.Count Alerts</h4>
<form asp-controller="Alerts" asp-action="PickAlert" method="post">
<select class="cap_select" id="cap_select" style="width:100%;max-width:95%;"
asp-for="SelectedAlertIndex" asp-items="Model.Alert_Identifiers">
<option>Select one</option>
</select>
<br />
<input type="submit" name="PickAlert" value="Pick Alert to Assemble EDXL-Cap Message" />
</form>
}
This takes the user to thePickAlert.cshtml page, a table of five rows where the first four rows are the Data Categories of the application: Alert, Info, Area and Resource each with the Alert_Identifier repeated as a reminder in a text box followed by its own submit button named Check Alert, Check Info, Check Area, and Check Resource, respectively. These submit buttons take the user to a _DetailsAlert.cshtml, _DetailsInfo.cshtml, _DetailsArea.cshtml, and _DetailsResource.cshtml pages and they work correctly, with the data item names and values from the record that matches the Alert_Identifier. The fifth row repeats the Identifier and its button reads Add All, to assemble the whole set together for review and takes the user to the_Assemble.cshtml page below, where the individual data categories are correctly assembled with the data item names, but lack the correct data values that match the record that corresponds to the Alert_Identifier. I’m thinking that I need to add a third parameter for the SelectedAlertIndex or Alert_Identifier to each of the #Html.Partial(...) Views, but I haven’t found the correct form/syntax for that, and If someone could supply that or point me to an example similar enough to this, I would deeply appreciate it.
#model edxl_cap_v1_2.Models.ContentViewModels.EdxlCapMessageViewModel
<!DOCTYPE html>
<head>
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="~/css/capv1_2_refimp.css" />
<title>Assembled EDXL-CAP Message</title>
</head>
<h4>Assemble EDXL-CAP Message</h4>
<!-- DetailsAlert -->
<div class="content-wrapper">
#Html.Partial("_DetailsAlert", Model.Alert)
</div>
<!-- End of DetailsAlert -->
<!-- DetailsInfo -->
<div class="content-wrapper">
#Html.Partial("_DetailsInfo", Model.Info)
</div>
<!-- End of DetailsInfo -->
<!-- DetailsArea -->
<div class="content-wrapper">
#Html.Partial("_DetailsArea", Model.Area)
</div>
<!-- End of DetailsArea -->
<!-- DetailsResource -->
<div class="content-wrapper">
#Html.Partial("_DetailsResource", Model.Resource)
</div>
<!-- End of DetailsResource -->
Responding to first comment below, I'm showing the InfosController.cs code for _DetailsInfo(int? id) the controller action for the Info Data Category. It is virtually identical for each of the data categories except that the line ... .SingleOrDefaultAsync(m => m.InfoIndex == id); becomes ....SingleOrDefaultAsync(m => m.AlertIndex == id); and the method itself becomes_DetailsAlert(int? id).
// GET: Infos/Details/5
public async Task<IActionResult> _DetailsInfo(int? id)
{
if (id == null)
{
return NotFound();
}
var info = await _context.Info
//.Include(e => e.Elements)
// .ThenInclude(d => d.DataCategory)
.AsNoTracking()
.SingleOrDefaultAsync(m => m.InfoIndex == id);
if (info == null)
{
return NotFound();
}
return View(info);
}
PickAlert method from AlertsController follows:
public IActionResult PickAlert(Alert obj, int? SelectedAlertIndex)
{
if (SelectedAlertIndex.HasValue)
{
ViewBag.Message = "Alert loaded successfully";
}
return View(_context.Alert.Where(x => x.AlertIndex == SelectedAlertIndex));
}
I am not sure if I got the requirement correctly, but I think you have to create another model for all 4 partial views, e.g. for Alert, create a new model
class AlertModel:EdxlCapMessageViewModel
{
int SelectedAlertIndex {get;set;}
}
And then your view would look like:
<!-- DetailsAlert -->
<div class="content-wrapper">
#Html.Partial("_DetailsAlert",new AlertModel { Alert = Model.Alert,
SelectedAlertIndex = <ID SOMEHOW>
});
</div>
In .net core when I need to pass around a lot of data across the views, I usually find it cleanest to use services and DI. First, you can create a class that could store a set of data:
class MyDataForViews {
// the following is an example. You can have any properties
public string Info { get; set; }
}
You now have to add this class as a service. To do so go to your startup class and add the following within the services function:
services.AddScoped<MyDataForViews>();
Scoped means that the framework will create a new object of MyDataForViews for each HTTP request. No matter how many places you "inject" an object of MyDataForViews, it would use the same object across the current HTTP request. You can also replace the function with AddSingleton if you want to use the same object throughout the web app. The following is how you inject an object into your controller:
public class MyController : Controller
{
MyDataForViews myData;
// in controllers injection is done using the constructor
public MyController(MyDataForViews MyData) => myData = MyData;
public IActionResult Index()
{
myData = .... // assign all required data here
View();
}
}
Once this is done, instead of passing models to each view, you can inject the data into views using the following:
#inject MyDataForViews MyData;
Once you use this line on the top of any view, you can use the MyData object and there is no need to pass models to each partial view.
Here's a bit more detailed answer, since you've said at softwareengineering.stackexchange.com site that you still need help with this.
Let's first make sure you understand the basics correctly.
When it comes to passing data to the view, each controller in ASP.NET MVC has a property named ViewData, which is essentially a dictionary of key-value pairs. The ViewData itself has a property called Model, and this is what you access in the page using the Razor syntax #Model. You can use this property to pass a model that is strongly-typed, to avoid using magic strings for the keys of ViewData.
Note: ViewBag is a dynamic wrapper around the ViewData, so it's essentially the same thing (ViewBag.SomeProperty is the same as ViewData['SomeProperty']); the use of ViewBag is discouraged, though.
In a controller action when you do something like return View(), ASP.NET uses the cshtml page as a template to create actual HTML, and return it as the response to the client (this is all server-side).
There are a few ways to pass data to the view which are equivalent, for example:
ViewData.Model = someObject;
return View();
is the same as:
return View(someObject); // the View method can accept a model object
When it comes to partial views, by default, they get passed a copy of the parent page ViewData (this includes the reference to the Model), so you don't have to do anything special to pass this data to a partial view (but you can pass data of your choice if you want to).
The select tag helper renders (generates HTML) for the select element with the options specified. This is then sent as HTML to the client. On the client side, when the user clicks the submit button, a POST request is sent to the server, which is ultimately handled by the method PickAlert method on the AlertsController. If everything is setup correctly, you should get the SelectedAlertIndex as the parameter. Note that this is happening back at the server side, and that you now need to again return a page as the response.
You can pick the corresponding Alert object from your _context. Use the FirstOrDefault method for this instead of Where, as you only need a single item (convert types for comparison if necessary - e.g., if you have a string, but you are comparing to an int, or something along those lines).
var selectedAlert = _context.Alert.FirstOrDefault(x => x.AlertIndex == SelectedAlertIndex);
Now, all you need to do is set this selectedAlert and any other data that you need as a property on your model object (or under some key in ViewData), and render the correct view.
Note that if you just return View(model) without specifying the name of the view, the system will look for a view with the same name as your action method (here, PickAlert.cshtml), so use return View("ViewName", model) to change that if necessary.
For example, based on the code you've posted in your question, you could do something like this:
[HttpPost]
public IActionResult PickAlert(int? SelectedAlertIndex)
{
var model = new EdxlCapMessageViewModel(/* ... params, if any */);
if (SelectedAlertIndex.HasValue)
{
ViewBag.Message = "Alert loaded successfully";
var selectedAlert = _context.Alert.FirstOrDefault(x => x.AlertIndex == SelectedAlertIndex);
// I added a property to your model to store the alert;
// if you already have one, just use that one instead.
model.SelectedAlert = selectedAlert;
}
return View("YourViewName", model);
}
The YourViewName should be the parent view that has the partial views in it (the "Assembled EDXL-CAP Message" view, I presume).
BTW, I know that the way the system is passing the parameters to the action methods in a controller may seem a bit like magic, but it's convention-based. In the example above, it works because the parameter is named SelectedAlertIndex, and the model object has a property with the same name (and because you've specified that property in the select tag helper using asp-for="SelectedAlertIndex"). You can also modify the method signature so that it receives the entire model object (assuming that the model class is not too complicated - you can read more about how parameter binding works here):
[HttpPost]
public IActionResult PickAlert(EdxlCapMessageViewModel model)
{
// extract the index from model.SelectedAlertIndex
// you can also pass this same model object to the view
// (set some properties first if necessary)
// ...
}
Now for the partial views. Assuming that you are relying on the default mechanism which passes the parent ViewData to each partial view, you need to modify each partial view so that the code is written under the assumption that you can access the selected alert using #Model.SelectedAlert (the property you've set in the PickAlert action).
For example, a here's a simple partial view:
<div style="border: solid 1px #000000; padding: 30px; margin: 2px 2px 10px 2px;">
<p>The selected index is: #Model.SelectedAlert.AlertIndex</p>
</div>
Note that I'm just using the same model as in the parent view to access the SelectedAlert object: #Model.SelectedAlert.AlertIndex.
Again, when rendering the partial views, if you pass no additional parameters, they'll get a copy of the ViewData dictionary, and the same Model:
#Html.Partial("_DetailsAlert");
If you pass something else as the model, e.g., only the selected alert, then you need to change the partial view code accordingly:
#Html.Partial("_DetailsAlert", Model.SelectedAlert);
<div style="border: solid 1px #000000; padding: 30px; margin: 2px 2px 10px 2px;">
<p>The selected index is: #Model.AlertIndex</p>
</div>
Note that now, in the partial view, the local #Model refers to what was #Model.SelectedAlert in the parent view. (In other words, here #Model is of type Alert.) This only affects the ViewData.Model property; the key-value pairs stored in ViewData are still the same as those in the parent view.
I have a form that upload a file and the server has to process a large operation that takes several minutes.
My code:
.cshtml:
#using (Html.BeginForm("MyAction", "MyController", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<input type="file" name="file"/>
<input type="submit" value="submit" />
}
Controller:
[HttpPost]
public ActionResult MyAction(HttpPostedFileBase file)
{
// Process a large operation here.
return View();
}
I know it's possible to do it with web.config configuration and with server code.
My question: Is it possible to do with client side configuration?
I ask that because when using XMLHttpRequest like jQuery.ajax its possible to set the timeout, so is it possible to do in html form tag or something?
One of the options is to create AsyncController and then you can set [AsyncTimeout(xxxx)] or [NoAsyncTimeout] attributes in your action.
Here is an example on how to do it
To put simply, I am scanning a drivers license with a magnetic strip card reader, using javascript RegEx to get the data I need, sending that data to the server as JSON via an ajax call, and then sending back a partial view with an Ajax.BeginForm with the data filled out.
In fact, all of this is working great. The problem is that I'm trying to alter the data on the server in C# before sending it to the view, but no matter what I do the original non-formatted data is showing up on the page still. I even stepped through the entire process, and looking at the Model data for the view shows that it received the correct data. Yet when the view is displayed, the non-formatted data (which does not actually exist in the Model object when I browse it) is what shows up in the text boxes.
function LoadVisitorCreatePartial(CardData) {
$.post(webroot + "Visitor/GetVisitorLogCreateVisitorForm", CardData, function (data) {
$('#visitor-info').append(data);
});
}
Above is the relevant javascript I am using for the call. I am using Carl Raymond's jquery card swipe to pull the data and I implemented some of my own RegEx to get the data I need for "CardData", which is JSON.
[HttpPost]
public ActionResult GetVisitorLogCreateVisitorForm(DriversLicenseForm CardData)
{
var form = visitorService.GetForm(CardData);
return PartialView("Form", form);
}
Above is the controller function that is being called. DriversLicenseForm is essentially the JSON object, as a C# class.
public VisitorForm GetForm(DriversLicenseForm CardData)
{
var textInfo = CultureInfo.InvariantCulture.TextInfo;
var DateOfBirth = DriversLicense.ParseDriversLicenseDate(CardData.DateOfBirthString);
CardData.FirstName = ConvertToTitleCase("i'm ron burgundy?");
CardData.LastName = textInfo.ToTitleCase(CardData.LastName);
var form = new VisitorForm();
if (DateOfBirth != null)
{
CardData.DateOfBirth = Convert.ToDateTime(DateOfBirth);
}
form = Mapper.Map<VisitorForm>(CardData);
form.ID = -1;
form = SetFormProperties(form);
return form;
}
In the above code you can see that I was getting annoyed. I decided to manually set the name and despite me setting CardData.FirstName to something completely different (verified when stepping through in debug mode) when the form comes back, it just shows my name from drivers license. I also have two title case functions because initially I thought that was the problem and found a non-textinfo solution, though that changed nothing and after debug stepping through, the data in CardData is being changed and updated properly. I feel it is worth noting one more time that the data is changed in debug mode in CardData and in the form after AutoMapper maps it out, my code appears to be working fine, except the actual view displays the original data despite there being no reference or reason for it to even know that data exists.
I literally have no idea what to do at this point.
EDIT: Here is the view code
#using (Ajax.BeginForm("PostForm", "Visitor", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "visitor-info", OnSuccess = "VisitorPostback" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.LastName, new { #class = "focus" })
#Html.ValidationMessageFor(model => model.LastName)
</div>
<p>
<input type="submit" class="btn btn-primary" value="Save" />
</p>
}
I cut out a lot of the actual textboxes, but left one as an example. They are all done the same way.
When sending data to a MVC Post action method, the ModelState gets populated with the data that you send. This is for instances when a form is POSTed that has validation errors, you can simply return the view back and all of the users form inputs are shown as well along with the validation errors.
Typically after a POST, you would redirect (PRG -> Post Redirect Get) to another action method, but it doesn't look like you would be able to do that here easily.
It looks like those ModelState values are being held onto the return of the "Form" view and is binding those to the matching form elements. Try adding ModelState.Clear() to your POST action method to see if that is what is causing the issue.
[HttpPost]
public ActionResult GetVisitorLogCreateVisitorForm(DriversLicenseForm CardData)
{
ModelState.Clear();
var form = visitorService.GetForm(CardData);
return PartialView("Form", form);
}