HTTP Put is not working for me in MVC 4 Web API. I keep getting a 404 - rest

var assetimage_id = $(this).closest(".assetImageWrapper").attr("data-assetimage_id");
var dataToSend = JSON.stringify({ "Asset_ID": assetimage_id, "Description": $(this).val() });
$.ajax({
url: "/api/Assets/UpdateDescription",
type: "PUT",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: dataToSend,
success: function (data) {
alert("success");
}
});
And here is the method that it is supposed to hit.
[HttpPut]
public Asset UpdateDescription(int Asset_ID, string Description)
{
return new AssetsService().UpdateAssetDescription(Asset_ID, Description);
}
What looks out of whack? The method is setting in a Web API controller called Assets. All other methods work fine from it (GETS, POSTS). This is when I'm running it by hitting F5 in Visual Studio 2012, so no IIS configuration was changed. the Api route is what the default route is.
And my web.config supports all verbs:

by default, simple types like 'Asset_ID' above and also string 'Description' are binded from Uri. In you scenario you seem to sending the content in the body, so you would need to change your api signature accordingly. BTW, you also cannot have multiple FromBody parameters on your action.
For a complex model, you need a view model created to contain them:
Once created:
public class AssetEstimatedValueUpdate
{
public int Asset_ID { get; set; }
public string EstimatedValue { get; set; }
}
Then you can pass it in and all works well.
[HttpPut]
public Asset UpdateDescription(AssetDescriptionUpdate _AssetDescriptionUpdate)
{
return new AssetsService().UpdateAssetDescription(_AssetDescriptionUpdate.Asset_ID, _AssetDescriptionUpdate.Description);
}

Related

Upload and read excel file using .NET core MVC

I have implemented an algorithm of reading an excel file using NPOI in .NET Core. Now I want is to upload a excel file in a web-app and read the excel file during uploading time and save it to database.
I am a bit confused about how should I approach for Model, Views and Controllers. Here are the optimized requirement list:
To ensure user is uploading .xlsx file (not other files)
Reading excel data during upload time
Save data in a database
Your controller can be something like this:
public ActionResult Import(System.Web.HttpPostedFileBase uploadFile)
{
if (uploadFile != null)
{
if (uploadFile.ContentLength > 0)
{
var fileExtension = Path.GetExtension(uploadFile.FileName);
if (fileExtension.ToLower().Equals(".xlsx"))
{
BinaryReader b = new BinaryReader(uploadFile.InputStream);
int count = uploadFile.ContentLength;
byte[] binData = b.ReadBytes(count);
using (MemoryStream stream = new MemoryStream(binData))
{
//call the service layer to read the data from stream
}
}
}
}
}
And your service layer is what you already figured out, using NPOI to read.
Based on the data you are reading from the excel file, your model could be something like this:
public class Product
{
public int ProductID {get; set;}
public string Name {get; set;}
public decimal Price {get; set;}
}
In the database, you can have a stored procedure which can take multiple rows of data using user-defined table type. You can call this stored procedure from your repository, after your read the data in service layer.
Finally in the view, you can have a form with the file upload dialog and pass the file uploaded by the user. Javascript to call the controller could be something like this:
function x () {
var inputdata = null;
var form = $('#__ImportFileForm');
var token = $('input[name="__RequestVerificationToken"]', form).val();
var fd = new FormData();
fd.append("__RequestVerificationToken", token);
fd.append("uploadFile", $("#uploadFile")[0].files[0]);
inputdata = fd;
inputdata.skipAjaxPrefilter = true;
$.ajax({
type: "Post",
url: url,
data: inputdata,
processData: false,
contentType: false,
traditional: true,
async: true,
success: function(data) { //do what you want },
error: function(data, ajaxOptions, thrownError) { //do what you want }
});
}
Hope this answers all your questions!

ASP.NET 5 WebAPI

I am creating API post methods in ASP.NET 5 webapi. I have a requirement that I need to create overloaded post methods as follows.
[HttpPost]
public bool LogInfo([FromBody]LogEventModel value)
{
}
[HttpPost]
public bool LogInfo (String strInformation)
{
}
I tried multiple options to set the routing parameters as follows.
[HttpPost("LogInfo/{strInformation}")]
(or)
[Route("LogInfo/{strInformation}")]
But its not working. I hope I am messing up something here. Can anyone help ?
I don't think this is possible anymore. Because of the fact that Controllers and Web API Controllers are now the same thing, routing has been unified also. You can read more about it here.
So what I would do is, this is my controller code:
public class HomeController : Controller
{
// GET: /<controller>/
public IActionResult Index()
{
ViewBag.Title = $#"{nameof(HomeController)}-{nameof(Index)}";
return View();
}
[HttpPost]
[Route("home/setsomething2", Name = "SetSomething2")]
public void SetSomething([FromBody]SomeValueModel someValue)
{
var value = someValue;
}
[HttpPost]
[Route("home/setsomething1", Name = "SetSomething1")]
public void SetSomething(String someValue)
{
var value = someValue;
}
}
public class SomeValueModel
{
[JsonProperty("somevalue")]
public string SomeValue { get; set; }
}
And this is how I called it from the view Index.cshtml:
function postSomething1() {
var url = "#Url.RouteUrl("SetSomething1", new {someValue = "someValue"})";
$.post(url)
.done(function () {
alert("Succes!");
})
.fail(function (response) {
console.log(response);
alert("Fail!");
});
}
function postSomething2() {
var url = "#Url.RouteUrl("SetSomething2")";
$.ajax({
contentType: 'application/json',
data: JSON.stringify({ "somevalue": "myvalue" }),
dataType: 'json',
success: function () {
alert("Succes!");
},
error: function () {
alert("Error!");
},
processData: false,
type: 'POST',
url: url
});
}
You could however make the routing of SetSomething2 more RESTful, like:
[Route("home/setsomething/{someValue}", Name = "SetSomething2")]
Note: Notice how the path 'home/setsomething/' is cleaned from numbers, so this would be my prefered way to go.
And if you REALLY don't want to make different routes you can't use named routes. So you'll have to ditch the names like:
[Route("home/setsomething")]
And:
[Route("home/setsomething/{someValue}")]
And then call them in jQuery like for instance:
var url = "home/setsomething/somevalue";
Here is what I do.
I prefer specifying routes for each controller by annotating them with:
[Route("[controller]/[action]")]
Then an action may look like:
[HttpPost]
[ActionName("GetSomeDataUsingSomeParameters")]
public List<Thing> GetSomeDataUsingSomeParameters([FromBody] MyParameters parms)
{
return Repo.GetData(parms);
}
The request may look like:
http://myhost/mycontroller/GetSomeDataUsingSomeParameters
The parameters are passed as a Json structure in the body by the POST method. For example:
{"Parameter1":1,"Parameter2":"a string"}
The request should also specify:
Content-Type: application/json
So let's say your class Thing is:
public class Thing
{
public int Id { get; set; }
public string Name { get; set; }
}
Then the response could be (with two things found in the database):
[{"Id":1,"Name":"First thing"},{"Id":2,"Name":"Another thing"}]

How does REST authentication work for client-side apps?

I'm trying to design my first public API, and I'm trying to learn how REST works with authentication, especially in the context of completely client-side apps using js-frameworks, e.g., angularJS.
Say you have a client which is a browser application (i.e., HTML, JS, CSS only) served as static files from something like nginx using a javascript framework to consume a REST service from, e.g. something that requires a secret access key that's used to create a signature for each request to the service, something like Amazon S3.
In terms of authentication in this scenario, where you don't have a server-side application, how would the secret access key be handled, i.e., how do you get it, where do you store it, etc.? It would seem like a horrible security situation to serve the key for each request (even if it only happens once to bootstrap the application).
And even if you do have a light server-side application--how do you securely inform the client (which still calls the authenticated 3rd party API itself) what the signature should be for every request it could possibly make? I'm very confused by how this is supposed to be designed from either end.
I've done a few AngularJS apps and the way that I've found is to use an HttpModule like this one:
using System;
using System.Net.Http.Headers;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Web;
namespace YourSolution.WebApp.Modules
{
public class BasicAuthenticationHttpModule : IHttpModule
{
public BasicAuthenticationHttpModule()
{
}
public void Init(HttpApplication context)
{
context.AuthenticateRequest += OnApplicationAuthenticateRequest;
context.EndRequest += OnApplicationEndRequest;
}
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
private static bool CheckPassword(
string username, string password)
{
return username == password;
}
private static void AuthenticateUser(string credentials)
{
try
{
var encoding = Encoding.GetEncoding(
"iso-8859-1");
credentials = encoding.GetString(
Convert.FromBase64String(credentials));
var separator = credentials.IndexOf(':');
var name = credentials.Substring(0, separator);
var password = credentials.Substring(separator + 1);
var validated = CheckPassword(name, password);
if (!validated) return;
var identity = new GenericIdentity(name);
SetPrincipal(new GenericPrincipal(identity, null));
}
catch (FormatException)
{
}
}
private static void OnApplicationAuthenticateRequest(
object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
var authHeader = request.Headers["Authorization"];
if (authHeader == null) return;
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
if (authHeaderVal.Scheme.Equals(
"basic",
StringComparison.OrdinalIgnoreCase)
&& authHeaderVal.Parameter != null)
{
AuthenticateUser(authHeaderVal.Parameter);
}
}
private static void OnApplicationEndRequest(
object sender, EventArgs e)
{
var response = HttpContext.Current.Response;
if (response.StatusCode == 401)
{
//response.Headers.Add(
// "WWW-Authenticate",
// string.Format("Basic realm=\"{0}\"", Realm));
}
}
public void Dispose()
{
}
}
}
The most important part is inside CheckPassword method, there is where you should validate the credentials.
Another point is this line response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Realm)); if you don't comment this line, the classic login requested form will show up, and if you do comment this line you have to catch the 401 error in your requests.
If you want to know about realm: What is the “realm” in basic authentication.
Plus, you will need to register the module in your web.config file:
<system.webServer>
<modules>
<add
name="BasicAuthenticationHttpModule"
type="YourSolution.WebApp.Modules.BasicAuthenticationHttpModule" />
</modules>
</system.webServer>
Then I've added these two methods to deal with the authentication token:
// u: username; p: password
CreateBasicAuthenticationToken = function (u, p) {
var t = u + ':' + p;
var hat = btoa(t);
window.sessionStorage.setItem('basicauthtoken', 'basic ' + hat);
};
DestroyBasicAuthenticationToken = function () {
window.sessionStorage.removeItem('basicauthtoken');
};
The btoa method: The btoa() method of window object is used to convert a given string to a encoded data (using base-64 encoding) string.. Taken from: http://www.w3resource.com/javascript/client-object-property-method/window-btoa.php.
And last I've added the authtoken to the request header using the beforeSend:
$.ajax({
type: 'GET',
url: 'your url',
beforeSend: function (xhr) {
window.sessionStorage.getItem('basicauthtoken');
}
}).done(function (data, textStatus, xhr) {
//...
});
Please do note using jQuery outside an angular directive is not recommended, AngularJS best practices dictates jQuery code must be always placed inside a directive.
Hope it helps.

REST API post using Twilio.MVC is not working. 404 error message with resource not found

What am I doing wrong in this code? When I send a POST request to this API i get the 404 error page. Can somebody help me debug this code. New to Rest Api and Twilio.
using System.Web.Mvc;
using Twilio.TwiML.Mvc;
using Twilio.Mvc;
namespace MVC4Test.Controllers
{
public class HomeController : TwilioController
{
[HttpPost]
public TwiMLResult ActionResult(SmsRequest request)
{
string smsTextType = request.Body;
var response = new Twilio.TwiML.TwilioResponse();
Response.ContentType = "text/xml";
response.Redirect("http://www.google.com");
//Response.ContentEncoding = System.Text.Encoding.UTF8;
//Response.Write(smsTest);
return TwiML(response);
//Response.Close();
}
}
}
This is my route
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 }
);
}
Twilio evangelist here.
Can you post the URL your are trying to load?
My first guess is that you mistakenly named your Action method. Right now its this:
public TwiMLResult ActionResult(SmsRequest request)
That would mean the URL you need to request is:
http://[yourdomain]/Home/ActionResult
If you change the name of the method:
public ActionResult Sms(SmsRequest request)
Then your URL would be:
http://[yourdomain]/Home/Sms
A couple of other things I noticed:
If you are using the TwiML() helper method to return the response, you do not need to set the ContentType yourself. That method will do it for you.
Not sure why you are telling Twilio to redirect to Google. You might want to look at the docs for <Redirect>
Hope that helps.

Passing the Ajax request data parameter through Zend Framework Controller to model class

I am Using the Zend Framework.
As a design pattern i am using the state design pattern.
Now as you may know, Zend Framework let's you create custom controllers, which can be used to respond to Ajax requests.
In my example i have the following ajax request
function getResponse(name){
$.ajax({
dataType: 'json',
data: {button: name},
url: 'motor/ajaxtest',
type: 'post',
success: function(response)
{
}
});
}
The function getResponse is called every time a specific button is pressed.
public function ajaxtestAction()
{
$input_in = $this->getRequest()->getParam('button');
$Lok = new Lok();
$this->_helper->viewRenderer->setNoRender();
$text = array($Lok->getMotorState());
$phpNative = Zend_Json::encode($text);
echo $phpNative;
}
The Code above is my custom response to the ajax request. I want to pass on the name of the pressed button to $Lok = new Lok(); so i can use it in the "Lok" model Class without creating a new instance of The controller in the "Lok" class
Is there anyone who might be able to help me ?
EDIT-----------------------------------
Here's my Controller :
class MotorController extends Zend_Controller_Action
{
public function init()
{
}
public function indexAction()
{
}
public function ajaxtestAction()
{
$input_in = array($this->getRequest()->getParam('button'));
$phpNativ1 = Zend_Json::encode($input_in);
echo $phpNativ1;
$Lok = new Lok();
echo $input_in;
$this->_helper->viewRenderer->setNoRender();
$text = array($Lok->getMotorState());
$phpNative = Zend_Json::encode($text);
echo $phpNative;
}
}
Here are my Jquery functions :
$(document).ready(function(){
$("p").click(function(){
$(this).hide();
$("input[name=State]").val('Forwards');
});
function getResponse(name){
$.ajax({
dataType: 'json',
data: {button: name},
url: 'motor/ajaxtest',
type: 'post',
success: function(response)
{
}
});
}
$("button[name=on]").click(function() {
var d_response = getResponse('on');
});
});
And this is my Lok.php file :
class Lok
{
private $newMotor;
private $newTimer;
private $newSpeaker;
private $mySession;
private $motorState;
private $input;
public function __construct()
{
//Method instances
$newMotor = new Motor();
$newTimer = new Timer();
$newSpeaker = new Speaker();
$this->motorState = $newMotor->getMotorState();
// Declaring the Session
$mySession = new Zend_Session_Namespace();
$mySession->s_motorState = $this->motorState;
}
public function __get($mySession)
{
return $this->mySession;
}
public function __set($motorState, $mySession)
{
$this->$mySession->s_motorState = $motorState;
}
public function getMotorState()
{
return $this->motorState;
}
public function playSound($soundNumber)
{
echo "Playing sound";
}
public function resetTimer()
{
echo "Resetting timer";
}
public function setInput($input_in)
{
$this->input=$input_in;
}
}
As i've stated previously you should get the button name by calling the requests post data, this is done by $postData = $this->getRequest()->getPost()
Then, to get the output into your Model, inside your model class you would create a property as well as setter and getter method for it.
class Lok {
protected $button;
public function setButton($btn){}
public function getButton(){}
}
And then it becomes as easy as doing something like
$lokModel->setButton($postData['button'])
First of all, thanks for posting your solution.
I tried to implement your solution but unfortunaly it didnt work.
So after a good night sleep, i looked at the problem again. I think the problem is, that
$postData = $this->getRequest()->getPost() or $postData = $this->getRequest()->getParam('button')
is executed in the response itelfe.
<pre>string(2) "sr"
</pre>["Not Moving"]
This is what the JSON response looks like in The Google Chrom debugger. If you'r familliar with this Google Chrome debugger you know what i mean.
Now the button name that i want is in between the &quot tags the only problem is, getting it out of there. and being able to use it before the response is triggerd. I also tried getPost() and getParam('button') in the init() and indexAktion() Methods in the Controller but it still didn't work
public function init()
{
postData = $this->getRequest()->getPost()
$lokModel->setButton($postData['button'])
}
public function indexAction()
{
postData = $this->getRequest()->getPost()
$lokModel->setButton($postData['button'])
}
Any other ideas ?