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"}]
Related
I've a route like Admin/Vendor in my MVC application . Without changing this route I need to point this same route to another method say CustomAdmin/CustomVendor.
I tried attribute routing but no luck . Is there any way to do this. My current code is given below
Original Method:
public class AdminController
{
public ActionResult Vendor()
{
return View();
}
}
Custom Method:
public class CustomAdminController
{
[Route("Admin/Vendor")]
public ActionResult CustomVendor()
{
return View();
}
}
As you're developing a plugin. You have to add your custom route to the RouteProvider.
In default nopCommerce AdminController and Vendor doesn't exists, so I assume that you're trying to override vendor list method of admin.
Which looks like:
public partial class RouteProvider : IRouteProvider
{
public void RegisterRoutes(RouteCollection routes)
{
var route = routes.MapRoute("Plugin.GroupName.PluginName.CustomVendor",
"Admin/Vendor/List",
new { controller = "CustomAdminController", action = "CustomVendor", orderIds = UrlParameter.Optional, area = "Admin" },
new[] { "Nop.Plugin.GroupName.PluginName.Controllers" });
route.DataTokens.Add("area", "admin");
routes.Remove(route);
routes.Insert(0, route);
}
public int Priority
{
get
{
return 100; // route priority
}
}
}
Side Note: GroupName and PluginName should be your plugin group name and plugin name.
Hope this helps !
On your plugin which class implements the interface IRouteProvider, you can easily override the route there.
Likewise I have a class named RouteProvider in my plugin, So I have Implemented the abstract function RegisterRoutes and simply it can be overrided by
routes.MapRoute("Plugin.Promotion.Combo.SaveGeneralSettings",
"Admin/Vendor",
new { controller = "CustomAdmin", action = "CustomVendor", },
new[] { "Nop.Plugin.Promotion.Combo.Controllers" }
);
Here Plugin.Promotion.Combo must be replaced by your plugin directory.And using SaveGeneralSettings or any things you want to use that will be your route url
To stay basic I would like to create a bookmark app
I have a simple bookmarklet
javascript:location.href='http://zas.dev/add?url='+encodeURIComponent(location.href)
I created a rest controller
<?php
use zas\Repositories\DbLinkRepository;
class LinksController extends BaseController {
protected $link;
function __construct(DbLinkRepository $link) {
$this->link=$link;
// ...
//$this->beforeFilter('auth.basic', array('except' => array('index', 'show', 'store')));
// ...
}
public function index()
{
//return Redirect::to('home');
}
public function create()
{
}
public function store()
{
return 'hello';
//$this->link->addLink(Input::get('url'));
//return Redirect::to(Input::get('url'));
}
public function show($id)
{
//$url = $this->link->getUrl($id);
//return Redirect::to($url);
}
public function edit($id)
{
}
public function update($id){
}
public function destroy($id){
}
}
in the routes.php, I created a ressource
Route::resource('links','LinksController');
and as I want to redirect /add to the store method I added
Route::get('/add',function(){
return Redirect::action('LinksController#store');
});
but it never display the hello message, in place it redirects me to
http://zas.dev/links
I also tried with
return Redirect::route('links.store');
without much success
thanks for your help
Ok I now get what you are trying to do. This will work:
Route::get('add', 'LinksController#store');
Remove:
Route::resource('links','LinksController');
and remove:
Route::get('/add',function(){
return Redirect::action('LinksController#store');
});
Sorry it took so long!
The problem is that once you Redirect::, you loose all the Input values, so you should manually give them to your controller when you do the redirect, like so :
Redirect::route('links.store', ["url" => Input::get("url")]);
Finally add an $url parameter to your store method to receive the value we give it in the previous method, like this :
public function store($url) {
$this->link->addLink($url);
return Redirect::to($url);
}
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);
}
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 " 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 ?
In my ASP.NET MVC 2 application I use HandleErrorAttribute to display a custom error page in case of unhandled exceptions, and it works perfectly unless the exception happens in an action called by Ajax.ActionLink. In this case nothing happens. Is it possible to use HandleErrorAttribute to update the target element with the contents of an "Error.ascx" partial view?
To achieve this you could write a custom action filter:
public class AjaxAwareHandleErrorAttribute : HandleErrorAttribute
{
public string PartialViewName { get; set; }
public override void OnException(ExceptionContext filterContext)
{
// Execute the normal exception handling routine
base.OnException(filterContext);
// Verify if AJAX request
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
// Use partial view in case of AJAX request
var result = new PartialViewResult();
result.ViewName = PartialViewName;
filterContext.Result = result;
}
}
}
And then specify the partial view to be used:
[AjaxAwareHandleError(PartialViewName = "~/views/shared/error.ascx")]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult SomeAction()
{
throw new Exception("shouldn't have called me");
}
}
And finally in your view assuming you have the following link:
<%= Ajax.ActionLink("some text", "someAction", new AjaxOptions {
UpdateTargetId = "result", OnFailure = "handleFailure" }) %>
You could make the handleFailure function to update the proper div:
<script type="text/javascript">
function handleFailure(xhr) {
// get the error text returned by the partial
var error = xhr.get_response().get_responseData();
// place the error text somewhere in the DOM
document.getElementById('error').innerHTML = error;
}
</script>