Make Ajax call to C# Controller Method - javascript

This is the code in my javascript file called "data handling.js" located in a folder called "JS":
document.getElementById('submit-new-project').addEventListener("click", function () {
var ProjectName = document.getElementById('new-project').value;
if (ProjectName) {
$.ajax({
type: "POST",
url: "Controllers/HomeController/AddProject",
data: {"ProjectName": ProjectName},
success: function () {
hideElement("add-button-popup");
location.reload();
},
error: function (errorThrown) {
console.log(errorThrown)
}
});
}
else {
alert("Text Field Must Not Be Empty");
}
})
And here is my controller method:
public partial class HomeController : Controller
{
[HttpPost]
public static void AddProject(string ProjectName)
{
using (AutomationMethodDirectoryEntities db = new AutomationMethodDirectoryEntities())
{
try
{
PROJECT project = new PROJECT();
project.ProjectName = ProjectName;
db.PROJECTS.Add(project);
db.SaveChanges();;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
The controller method is located in "Adders.cs" which is a partial class to "HomeController.cs" in the "Controllers" folder. Both the "JS" and "Controllers" folders are at the root level of the project. I have tried many variations of this ajax call and my biggest problem is with the URL. No matter what I try, I am always getting a 404 error because the server can't find the requested URL.
I've tried changing it to:
url: "Controllers/HomeController/AddProject"
url: "/Controllers/HomeController/AddProject"
url: "../Controllers/HomeController/AddProject"
url: "Home/AddProject"
url: "/Home/AddProject"
url: "../Home/AddProject"
url: "#(Url.Action(AddProject, HomeController))"
And I've swapped "HomeController" with "Adders" in different variations.
What am I doing wrong?
Is there anything I need to add/change to my controller method?
EDIT
Here is my "RouteConfig.cs" that I haven't made any changes to yet:
namespace RTCAD
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}

When calling your AddProject action, ASP.NET MVC creates an instance of the controller (using ControllerFactory), and since your method is static, it is not related to any instance, and thus, it will not be called by MVC.
Remove the static from the method declaration and use /Home/AddProject as the URL.

Related

Upload multiple files each with additional information in spring

I'm new to spring boot and js and i'm trying to upload multiple files each having additionl information like description etc.
Objects :
public class BookDto {
private String title;
private String author;
private List<PageDto> pageDtoList;
// getters setters
}
public class PageDto {
private String description;
private MultipartFile file;
// getters setters
}
Controller :
public class UploadController{
#PostMapping("/upload")
public ResponseEntity createGenre(#RequestBody BookDto bookDto){
// do something with data
}
}
Html :
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" multiple onclick="postRequest(event)">
<input type="submit" value="Upload" name="submit">
</form>
JS :
function postRequest(event){
event.preventDefault();
var files = [].slice.call(event.target.files);
var pageList = [];
for (var i=0; i<files.length; i++) {
pageList.push(new Page( i + "some description",files[i]));
}
var newBook = new Book();
newbook.pageList = pageList;
book.author = "author1";
book.title = "title1";
$.ajax({
type: "POST",
data: // i don't really know what to put here,
url: "/upload",
success: function (response) {
// success
},
error: function (result) {
// error
}
});
}
function Book(title, author, chapter, pageList){
this.title = title;
this.author = author;
this.pageList = pageList;
}
function Page(description, file) {
this.description = description;
this.file = file;
}
I would like to know if it is possible to upload files as described by the objects or do i have to upload them seperately.
In order to create a book instance from a request, considering you have a route such as :
#PostMapping("/createBook")
public ResponseEntity createBook(#RequestBody BookDto bookDto){
// do something with data
}
you can from client proceed to following :
const book = {
author: "George Orwell",
title: "1984",
pageDtoList: []
};
$.ajax({
type: "POST",
data: book,
url: "/createBook",
success: function (response) {
// success
},
error: function (result) {
// error
}
});
You can then add pages with same logic, but with a file set to null temporary, and upload file after, given a page id.
#PostMapping("/addPageToBook")
public ResponseEntity addPage(#RequestParam("bookid") String bookId,
#RequestBody PageDto pageDto){
// add a page instance to your book
}
And after you can set page content :
#PostMapping("/setPageContent")
public ResponseEntity setPage(#RequestParam("bookid") String bookId,
#RequestParam("pageid") String pageId,
#RequestParam("file") MultipartFile content){
// set content to page, ensure book dto is updated with last page instance
}
You will need to use https://developer.mozilla.org/en-US/docs/Web/API/FormData for AJAX uploading, but maybe (depending on your use case) a simple file input button + submit can be enough.

How can I use c# asp.net to get data from url?

I'm trying to get some info I sent by form to angularJS in my c# asp.net backend, and I'm having trouble doing it.
Visual Studio won't let me compile because it says:
Error CS0120: an object reference is required for the nonstatic field, method, or property 'member'
That's is my controller
public class SearchController : ApiController
{
public string Get()
{
string test = HttpContext.Request.QueryString["txt_search"];
return test;
}
}
Here's what I got in my angularjs:
$scope.sendForm = function () {
console.log($scope.model.search);
$http({
method: 'GET',
url: '/api/search?txt_search=' + $scope.model.search
})
.then(function () {
console.log('sucesso a executar o post');
}, function () {
console.log('Erro ao executar o post');
});
};
As suggested in the comments, you should just be able to change your method definition and skip this altogether:
public string Get(string txt_search)
{
return txt_search;
}
Alternatively, to reference the current request, I believe you need to use the following (note the addition of .Current):
string test = HttpContext.Current.Request.QueryString["txt_search"];
The reason is that HttpContext defines Request as an instance property. The only public static property is Current, which returns an instance of HttpContext through which you can reach Request.
Welcome to Stack Overflow,
Your Angular code is correct
You need to pass a parameter on server side to collect txt_search value
Here it is:
[HttpGet]
[Route("/api/search")]
public string mySearchMethod(string txt_search)
{
//something here with txt_search
return "OK";
}
Both of the above solution will work, but for another approach as you are using asp.net web api and router you can make it as below as well
In your Angular code, simple pass the search as below
```
$scope.sendForm = function () {
console.log($scope.model.search);
$http({
method: 'GET',
url: '/api/search/'+ $scope.model.search
})
.then(function () {
console.log('sucesso a executar o post');
}, function () {
console.log('Erro ao executar o post');
});
};
```
Notice
url: '/api/search/'+ $scope.model.search
and change the Action method as below
```
[HttpGet]
[Route("/api/search/{txt_search}")]
public string mySearchMethod(string txt_search)
{
//something here with txt_search
return "OK";
}
```
by doing this you don't have to worry about the name of the parameter txt_search
whatever you mention in route [Route("/api/search/{txt_search}")], you will get the value in same parameter.

multiple routes in one controller causes 400:bad request

Let me give an example of my problem,
I have registered my routes as following(RouteConfig.cs):
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
if you look at my controller, it has the following function;
[Route("all")]
public HttpResponseMessage Get(HttpRequestMessage request)
{
return CreateHttpResponse(request, () =>
{
HttpResponseMessage response = null;
var HolidayCalendars = _holidayCalendarsRepository.GetAll().ToList();
IEnumerable<HolidayCalendarViewModel> holiVm = Mapper.Map<IEnumerable<HolidayCalendar>, IEnumerable<HolidayCalendarViewModel>>(HolidayCalendars);
response = request.CreateResponse<IEnumerable<HolidayCalendarViewModel>>(HttpStatusCode.OK, holiVm);
return response;
});
}
up to this point everything is going great. My page loads with the requested data. Now, when I go and add another function, for example;
[Route("allHolidays/{id:int}")]
public HttpResponseMessage GetHolidays(HttpRequestMessage request, int id)
{
return CreateHttpResponse(request, () =>
{
HttpResponseMessage response = null;
HolidayCalendar Calendar = _holidayCalendarsRepository.GetSingle(id);
var Holidays = Calendar.Holidays.OrderBy(s => s.HolidayDate).ToList();
IEnumerable<HolidayViewModel> holidayVm = Mapper.Map<IEnumerable<Holiday>, IEnumerable<HolidayViewModel>>(Holidays);
response = request.CreateResponse<IEnumerable<HolidayViewModel>>(HttpStatusCode.OK, holidayVm);
return response;
});
}
I will get the following error in my webpage;
Failed to load resource: the server responded with a status of 400 (Bad Request)
Strange thing is, my request did not change, there is only a new Controller in my api.
This should not be happening because my code is requesting different routes, for example;
function loadData() {
apiService.get('/api/HolidayCalendars/all', null,
HolidayCalendarLoadCompleted,
HolidayCalendarLoadFailed);
}
or
function loadData() {
apiService.get('/api/HolidayCalendars/allHolidays?id=' + $routeParams.id, null,
HolidaysLoadCompleted,
HolidaysLoadFailed);
}
Any ideas?
constructor class WebApiConfig:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional }
);
}
Your route for allHolidays implies this format
/api/HolidayCalendars/allHolidays/123
According to your route attribute
[Route("allHolidays/{id:int}")]
But you've passed the id as a querystring parameter
api/HolidayCalendars/allHolidays?id=123
Looks like you're using AttributeRouting (http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2) on the Controllers :
[Route("all")]
but you're using standard routing in the config:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Try activate the AttributeRouting with:
configuration.MapHttpAttributeRoutes();
where configuration is the actual instance of HttpConfiguration.
The issue is in your WebApiConfig. In the routeTemplate, you haven't specified an action.
routeTemplate: "api/{controller}/{id}",
If I remember correctly, this is the default config for WebAPI. It filters requests on a controller by verb. That's why when you call
apiService.get('/api/HolidayCalendars/all'.....)
It returns the Get() method on your HolidayCalendars controller.
To fix the issue, add the {action} parameter to your routeTemplate:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new {id = RouteParameter.Optional }
);
}
I finally found the solution!
At the top of my code i had a reference to System.Web.Mvc. This way the routing and RESTful functions were not interpreted as it should in a web Api. This caused some strange functioning in my app.
Solution:
Change
using System.Web.Mvc;
To
using System.Web.Http;
This evaded me for three days,until I came along the following answer:
https://stackoverflow.com/a/21999235/6033193

Proper technique to pass javascript array to controller with List<int> parameter

I have a controller that takes a List<int> and I am calling from AJAX. The controller is hit, but the parameter is always null.
My controller:
public ActionResult MinorAreas(List<int> majorareas)
{
// ...
}
jQuery call:
function onChange(e)
{
var cur = this.value(); // an array of numbers like [2,4,7,9]
$.ajax({
cache: false,
type: "GET",
traditional: true,
url: "#(Url.RouteUrl("GetMinorAreas"))",
data: { "majorareas": cur},
success: function (data) {...},
error: function (xhr, ajaxOptions, thrownError) {... }
});
}
Route definition:
routes.MapLocalizedRoute(
"GetMinorAreas",
"minorAreas",
new { controller="ProSearch", action="MinorAreas", majorareas=new List<int>() },
new[] { "ABC.ZZZ.Controllers" }
);
Using fiddler, I can see that the URI is built correctly:
# With an array of [2]
http://localhost:15536/minorAreas?majorareas=2&_=1450307693166
# With an array of [2,3,9]
http://localhost:15536/minorAreas?majorareas=2&majorareas=3&majorareas=9&_=1450308261808
I've already looked at this question about passing arrays to a controller with a List<int> parameter, but the solution doesn't seem to work for me. What am I doing wrong?
It looks like the network request is being generated correctly. The problem is in the route definition:
routes.MapLocalizedRoute(
"GetMinorAreas",
"minorAreas",
new { controller="ProSearch", action="MinorAreas", majorareas=new List<int>() },
new[] { "ABC.ZZZ.Controllers" }
);
majorareas=new List<int>() is going to ensure that majorareas is always an empty list, even when it otherwise would be populated!
You don't have to define parameters here; the method definition in the controller does that. Leave it off, and it should work fine:
routes.MapLocalizedRoute(
"GetMinorAreas",
"minorAreas",
new { controller="ProSearch", action="MinorAreas" },
new[] { "ABC.ZZZ.Controllers" }
);

How do I get Post data from my HTTP context object

I am working on a POC using a very old asp.net application that runs winforms, and adding a REST API to it. I have so far been successful up until this one endpoint, and it is not giving me my data back in my controller.
I have more experience in an MVC framework and web API then the current implementation I am working in. What I need help with is how I can get my data sent back to the server.
Here is my code:
this is the equivalent of my global asax file
class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
appBuilder.UseCors(CorsOptions.AllowAll);
appBuilder.UseWebApi(config);
}
}
Javascript
var setPatient = function () {
$.ajax({
url: "http://localhost:9000/api/context/readPtnt?contextData=&type=context",
type: "POST",
dataType: "json",
contentType:"application/json; charset=utf-8",
data: {
jsonData: JSON.stringify({
firstName: $('#fName').val(),
lastName: $('#lName').val(),
ID: $('#ID').val(),
DOB: $('#DOB').val(),
SSN: $('#SSN').val(),
MRN: $('#MRN').val()
})
}
})
.done(successPatientSet)
.fail(errorFn)
.always(function (data, textStatus, jqXHR) {
});
}
//click
$("#btnSetPatientData").on("click", setPatient);
and my controller code:
[HttpPost]
[Route("/api/context/readPtnt")]
public string ReadPtnt(string contextData, string type)
{
try
{
var patientInfo = PatientContext.Create(contextData);
I can successfully hit the back end, but I get nothing in the contextData variable, when I try to change that variable name I get 404's. I have tried all sorts of variations from different iterations of my JQuery, as well as pure javascript Ajax calls. The REST middleware that we are using is OWIN. I am stumped, any input would be helpful. Thanks.
You need enable CORS support
To enable CORS support, add the Microsoft.AspNet.WebApi.Cors NuGet package to your project.
Add this code to your configuration:
public static void Register(HttpConfiguration config)
{
// New code
config.EnableCors();
}
To enable cross-origin requests, add the [EnableCors] attribute to your Web API controller or controller method:
[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods not shown...
}
Enabling Globally
The method described above can also be used to enable CORS across the API without annotating each controller:
public static void Register(HttpConfiguration config)
{
var corsAttr = new EnableCorsAttribute("http://example.com", "*", "*");
config.EnableCors(corsAttr);
}
For more information, see the official Web API documentation.

Categories