GUID model binding in ASP.NET MVC - javascript

I was hoping someone could help me sort this out.
The solution to this is probably obvious but I can't seem to figure out what I'm missing...
I'm trying to issue a get request from my Javascript code, and the URL contains a Guid.
The ASP.NET controller does not get hit/register the request to the API.
I've tried a couple different things already but this is my Javascript and Controller as is:
function getChat( contact_id ) {
$.get("/contact/conversations", { contactId: contact_id })
.done( function(resp) {
let chat_data = resp.data || [];
loadChat( chat_data );
});
}
and...
[Route("contact/conversations")]
public JsonResult ConversationWithContact(Guid? contactId)
{
... //this doesn't get hit
}
I keep getting this error:
I'm not sure how to properly bind the Guid such that it is received by the ASP.NET Controller.
Any ideas?? Much appreciated and have a great day!

Change your route to this:
[Route("~/contact/conversations/{id}")]
public JsonResult ConversationWithContact(string id)
{
if(!string.IsNullOrEmpty(id)){
var contactId= new Guid (id);
... //this doesn't get hit
}
}
and your ajax:
function getChat( contact_id ) {
$.get("/contact/conversations/"+contact_id)
.done( function(resp) {
let chat_data = resp.data || [];
loadChat( chat_data );
});
}
but if you use very old MVC and attribute routing doesnt work for you, try this:
function getChat( contact_id ) {
$.get("/contact/ConversationWithContact/"+contact_id)
.done( function(resp) {
let chat_data = resp.data || [];
loadChat( chat_data );
});
}

Related

Can't connect to web service by JQuery

I use jquery (ajax) to connect to a web service which returns string , it is not working with me. it always go to error function. here is my web service :
[HttpGet]
[ActionName("GetImage")]
public string GetImage(string base64String, string imgName,string reqTitle , string reqSubject, string reqStatus,string Creator , DateTime creationdate )
{
try
{
using (PhMobAppEntities context = new PhMobAppEntities())
{
ClaimsApproval _ca = new ClaimsApproval();
_ca.imageBasestrg = base64String;
_ca.imageName = imgName;
_ca.Creator = Creator;
_ca.CreationTime = creationdate;
_ca.ReqStatus = reqStatus;
_ca.ReqTitle = reqTitle;
_ca.ReqSubject = reqSubject;
context.ClaimsApprovals.Add(_ca);
context.SaveChanges();
return "Success";
}
}
catch (DbEntityValidationException ex)
{
var errorMessages = ex.EntityValidationErrors
.SelectMany(x => x.ValidationErrors)
.Select(x => x.ErrorMessage);
var fullErrorMessage = string.Join("; ", errorMessages);
var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
}
}
and here is my js code :
$("#sendphoto").click(function () {
var url = "http://41.128.183.109:1212/api/Data/GetImage";
var data = {
imgName: "test"
};
$.ajax({
url: url,
type: 'Get',
data: data,
success: function (data) {
alert("Success");
},
error: function (data) {
alert("Please Check Your Internet Connection");
}
});
});
It is running ok when i tested my web service in advanced rest client ,please advice .
I tried connecting to your web service and I get the following response:
{"$id":"1","Message":"No HTTP resource was found that matches the request URI 'http://41.128.183.109:1212/api/Data/GetImage'."}
I think what you have is an internal problem with your c# code, probably with your routing. Your javascript call is probably working fine, but you are passing only one parameter, "test" while you have many more in your declaration.
What http response code are you getting?

$http Call to Web API 2 Not Passing Parameter

This is my C# WebAPI2 controller, which gets hit:
[HttpGet, Route("bycaseidlist/{idArray}")]
public async Task<IHttpActionResult> GetByCaseIdList([FromUri] List<int> idArray)
This is the call:
var idArray = [4,4,2,4];
var url = baseUrl + 'api/cases/bycaseidlist/' + idArray ;
$http.get(url)
The problem is that the API doesn't get the array, it gets ...this:
In other words an array with one value: 0. Why is this happening? How do I fix it? It seems to be in-line with this answer, but it doesn't work. Should I pass it in the body? I feel like I am missing something obvious.
Get ActionMethods can take objects as arguments. However, the default behavior is to look at the body when the parameter is not a .net primitive. In order to force the action method to use a model binder to read the object data from the request, the parameter can be decorated with the [FromUri] or [ModelBinder] attributes. (Note there are other ways to do this that include doing parameter binding rules but that is probably overkill for what you are trying to accomplish here). Here is an implementation that solves the original problem that you were posing.
<script type="text/javascript">
var ajaxCall = function (myArry) {
var ajaxProperties = {};
ajaxProperties.url = "/api/Mul/Mutiply";
ajaxProperties.type = "Get";
ajaxProperties.data = {};
ajaxProperties.data.numbers = myArry;
ajaxProperties.contentType = "application/json";
console.log(ajaxProperties);
ajaxProperties.success = function (data) {
console.log(data);
}
ajaxProperties.error = function (jqXHR) {
console.log(jqXHR);
};
$.ajax(ajaxProperties);
};
var getData = function (e) {
var myArry = new Array();
myArry.push($('input[name=num1').val());
myArry.push($('input[name=num2').val());
ajaxCall(myArry);
return false;
};
</script>
Controller
[HttpGet]
public IHttpActionResult Multiply([FromUri] int[] numbers)
{
int result = 0;
if(numbers.Length > 0)
{
result = 1;
foreach (int i in numbers)
{
result = result * i;
}
}
return Ok(result);
}
}
I think my mistake was using Get. I might be remembering incorrectly (someone confirm if you know offhand), but Get might not be able to take objects as arguments. Anyway, I changed the method to POST and then changed the param to be sent in the request body, rather than the url. It now works. Here is the working code:
[HttpPost, Route("bycaseidlist")]
public async Task<IHttpActionResult> PostByCaseIdList([FromBody] int[] sqlCaseIdArray)
and the call itself:
function runDbCall(url, sqlCaseIdArray){
return $http({
method: 'POST',
url: url,
data: sqlCaseIdArray
});
}
runDbCall(url, sqlCaseIdArray)
I will come back to this when I figure out if the problem was Get not being able to take objects, but I thought it could in url, just not in body...need to clarify. If someone posts an answer just on that part, I will accept, since that's probably the root of the prob.

Call Controller from .cshtml via getJSON

I have performed this action within a .js file without issue and I am wondering if I have to do something a little different from a .cshtml because I can't seem to find any other reason this is failing. Here is my js within my .cshtml file:
mergeBtn.onclick = function (e) {
e.preventDefault();
var url = '/api/publicpatron/student-no-validation?studentNo=' + studentNo.value;
$.getJSON(url)
.done(function (json) {
if (json.errors) {
toastr.error(json.message, '', { timeOut: 0, extendedTimeOut: 0 })
}
else {
//do something
}
})
.fail(function (jqxhr, textStatus, error) {
var err = textStatus = ', ' + error;
toastr.error(err, '', { timeOut: 0, extendedTimeOut: 0 })
})
}
The code in the controller doesn't seem to be the issue as it never gets to the controller, I have verified I have the controller file name and function name correct in my URL. Any suggestions? Is this not possible from within a .cshtml file??
UPDATE:
Here is the controller:
file name: PublicPatronController
[Authorize(Roles = "my-roles")]
[ActionName("student-no-validation")]
public dynamic IsStudentNoValid([FromUri] string studentNo)
{
dynamic results = new ExpandoObject();
if (studentNo == null)
{
results.error = true;
results.message = "Invalid Student Number";
return results;
}
using (ADRoutineEntities db = new ADRoutineEntities())
{
var exists = db.UserLinkages.Any(x => x.StudentNo == studentNo);
if (!exists)
{
results.errors = true;
results.message = string.Format("Student number {0} does not exist", studentNo);
return results;
}
}
results.ok = true;
return results;
}
UPDATE 2:
It does appear to be related to the controller somehow. I changed the url to a different apicontroller I use elsewhere and it worked fine. The issue seems to be related to the name of the apicontroller. When I change it to the name of an existing apicontroller but keep the actionname the same it works. Why would that be???
You should add the [HttpGet]-attribute to the method on the controller.
Normally WebAPI takes the first part of the methodname to determine what HTTP-verb it should use. In your case, that's not a valid http-method, so you need to explicitly add the attribute.
Another option is to change the method name, eg: GetIsStudentNoValid
You should also return an HttpResponseMessage with a status code instead of a dynamic

Fetch data on different server with backbone.js

I can't see what the problem with this is.
I'm trying to fetch data on a different server, the url within the collection is correct but returns a 404 error. When trying to fetch the data the error function is triggered and no data is returned. The php script that returns the data works and gives me the output as expected. Can anyone see what's wrong with my code?
Thanks in advance :)
// function within view to fetch data
fetchData: function()
{
console.log('fetchData')
// Assign scope.
var $this = this;
// Set the colletion.
this.collection = new BookmarkCollection();
console.log(this.collection)
// Call server to get data.
this.collection.fetch(
{
cache: false,
success: function(collection, response)
{
console.log(collection)
// If there are no errors.
if (!collection.errors)
{
// Set JSON of collection to global variable.
app.userBookmarks = collection.toJSON();
// $this.loaded=true;
// Call function to render view.
$this.render();
}
// END if.
},
error: function(collection, response)
{
console.log('fetchData error')
console.log(collection)
console.log(response)
}
});
},
// end of function
Model and collection:
BookmarkModel = Backbone.Model.extend(
{
idAttribute: 'lineNavRef'
});
BookmarkCollection = Backbone.Collection.extend(
{
model: BookmarkModel,
//urlRoot: 'data/getBookmarks.php',
urlRoot: 'http://' + app.Domain + ':' + app.serverPort + '/data/getBookmarks.php?fromCrm=true',
url: function()
{
console.log(this.urlRoot)
return this.urlRoot;
},
parse: function (data, xhr)
{
console.log(data)
// Default error status.
this.errors = false;
if (data.responseCode < 1 || data.errorCode < 1)
{
this.errors = true;
}
return data;
}
});
You can make the requests using JSONP (read about here: http://en.wikipedia.org/wiki/JSONP).
To achive it using Backbone, simply do this:
var collection = new MyCollection();
collection.fetch({ dataType: 'jsonp' });
You backend must ready to do this. The server will receive a callback name generated by jQuery, passed on the query string. So the server must respond:
name_of_callback_fuction_generated({ YOUR DATA HERE });
Hope I've helped.
This is a cross domain request - no can do. Will need to use a local script and use curl to access the one on the other domain.

Delete multiple objects Amazon s3 PHP SDK

I'm having issues deleting multiple objects at once..
Using this library-
https://github.com/aws/aws-sdk-php-laravel
I have no issues with anything else using the library (putting, getting, deleting single objects, etc.)
try {
$s3 = AWS::get('s3');
$s3->deleteObjects(array(
'Bucket' => $bucket,
'Objects' => $json['attachmentArray']
));
return "Success deleting files.";
} catch (S3Exception $e) {
return "There was an error.\n";
}
deleteObjects Amazon Docs- http://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingMultipleObjectsUsingPHPSDK.html
I get returned "Success deleting files.";, but the files are not being deleted.
My bucket name is correct, and the $json['attachmentArray'] is in the right format according to the docs (again, I have no issues with other areas like put, get, delete)
Where am I messing up?
Trying to give more info:
I am POSTing info from an Angular function to Laravel endpoint.
Here is the Angular function (Firebase URL hidden):
$scope.deleteFile = function() {
var r=confirm("Are you sure you want to delete this task & of it's all attachments?");
if (r==true)
{
var attachmentArray = [];
var atttachData = new Firebase('https://*.firebaseio.com/attachments');
atttachData.on('value', function(dataSnapshot) {
dataSnapshot.forEach(function(childSnapshot) {
var key = childSnapshot.val().key;
// attachmentArray.push(key); I tried this
attachmentArray.push({Key:key});
});
});
method: "POST",
url: '/delete_task',
data: {attachmentArray:attachmentArray},
headers: {'Content-Type': 'application/json'},
}).success(function(data){
console.log(data);
});
}
}
And here is my Laravel controller that I am trying to make deleteObjects (with updated code from #Kevin Florida:
public function delete_task() {
$request = Request::instance();
$task = $request->getContent();
$json = json_decode($task, TRUE);
$bucket ='bucketname/team1';
// return $json['attachmentArray'];
$s3 = AWS::get('s3');
if(!$s3->deleteObjects(array(
'Bucket' => $bucket,
'Objects' => $json['attachmentArray']
))) {
return "error";
} else {
return "success";
}
}
Now this returns a 500 server error.. I think I'm formatting $json['attachmentArray']; incorrectly? I'm not sure.
Angular function
$scope.deleteFile = function() {
var r=confirm("Are you sure you want to delete this task & of it's all attachments?");
if (r==true)
{
var attachmentArray = [];
var atttachData = new Firebase('https://***/attachments');
atttachData.on('value', function(dataSnapshot) {
dataSnapshot.forEach(function(childSnapshot) {
var url = childSnapshot.val().url;
var name = childSnapshot.val().name;
var id = childSnapshot.val().id;
var key = childSnapshot.val().key;
attachmentArray.push(key);
});
});
$http({
method: "POST",
url: '/delete_task',
data: {team:$scope.team,attachmentArray:attachmentArray,lastSegment:lastSegment},
headers: {'Content-Type': 'application/json'},
}).success(function(data){
console.log(data);
});
}
}
Laravel controller
public function delete_task() {
$s3 = AWS::get('s3');
$task = Input::all();
$bucket ='teamite/team'.$task['team'];
//make the array for Objects on this side
foreach ($task['attachmentArray'] as $value) {
$array[] = array('Key' => $value);
}
// return $task['attachmentArray'][0];
$result = $s3->deleteObjects(array(
'Bucket' => 'teamite/team1',
'Objects' => $array
));
return $result;
}
And I log this response in the console from Amazon:
=====================
Debug output of model
=====================
Model data
-----------
This data can be retrieved from the model object using the get() method of the model (e.g. $model->get($key)) or accessing the model like an associative array (e.g. $model['key']).
[Deleted] => Array
(
[0] => Array
(
[Key] => 4700pzgds4i_ad.jpg
)
[1] => Array
(
[Key] => xxvu29ms4i_ad.jpg
)
)
[RequestId] => 477F0DA04101D82E
So it seems to be working correctly now. But the objects are not being deleted?
What else am I doing wrong?
It actually looks like you are not referencing the files (S3 objects) correctly. The formatting of the request is fine, but the bucket name and keys may be wrong.
Looking at:
$bucket = 'teamite/team'.$task['team'];
Is your bucket called "teamite/team1" or just "teamite"? Keep in mind that S3 has a flat structure. There are no "subbuckets". If you have things laid out in a nested file structure, then the paths, or pseudo-folders, need to be included as part of the key.
For example, in this imaginary URL to an object in S3: http://s3.amazonaws.com/all-of-my-things/photos/2013/12/photo0005.jpg
The bucket is all-of-my-things, and the key is photos/2013/12/photo0005.jpg.
The deleteObjects() call you are making is returning successfully because of the idempotent nature of S3 operations. If you delete an object multiple times, it will return successfully every time. What you are seeing here is that you are deleting objects using the wrong keys. Those keys don't exist, and therefore are already deleted.
Hopefully this helps. Don't be afraid to reach out on the module's issue tracker or directly on the SDK's issue tracker for problems like this when you are working directly with the SDK objects.
To delete s3 file use it
It work for me -
$s3 = AWS::get('s3');
$s3->deleteMatchingObjects('Your Bucket Name', 'File name to delete');
For testing try:
if(!$s3->deleteObjects(array(
'Bucket' => $bucket,
'Objects' => $json['attachmentArray']
))) {
return "error";
} else {
return "success";
}
catch will only return "There was an error" if an exception occurs, not if the deleteObjects() method returns false

Categories