I'm writing a controller to get the Books with for certain authors with a specific rating. This is the code for the GET method :
public IQueryable<Book> GetBooks(string context)
{
string rating = context.Split('?')[0];
string[] authors = context.context.Split('?')[1].Split(',');
return db.Books.Where(s => authors.Contains(s.AuthorName) && s.Rating == rating);
}
When I run the project and enter this URL :
http://localhost:65239/api/books/5?James,Tom
I get this error:
<Error>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>
What am I doing wrong?
Try this;
public JsonResult GetBooks(string context)
{
string rating = context.Split('?')[0];
string[] authors = context.context.Split('?')[1].Split(',');
var books = db.Books.Where(s => authors.Contains(s.AuthorName) && s.Rating == rating);
return Json(books, JsonRequestBehavior.AllowGet);
}
Turns out I was using the wrong URL format.
http://localhost:65239/api/books?context=5?James,Tom
Related
I have the snippet in C# and was looking for some advice converting it to PHP.
Basically, what is happening here, I am building somewhat of a middleware site.
A user submits a form named "Basket" and creates a POST request with XML body to this file, which will parse it, create a new URL with parameters which will afterwards be sent to Shopify cart.
Any help is appreciated.
public class DefaultController : ApiController
{
public IHttpActionResult Post()
{
var query = "";
var domain = "https://shop.shopify.io/cart";
try
{
var content = Request.Content.ReadAsFormDataAsync().Result;
var document = XDocument.Parse(content["basket"]);
if (document.Root != null)
{
var products = document.Root.Elements().Select(x => x.Element("productid").Value + ":" + x.Element("amount").Value);
query = string.Join(",", products);
}
}
catch
{ }
if (string.IsNullOrEmpty(query))
return Redirect(domain);
return Redirect($"{domain}?query={query}");
}
}
```
My .NET Core Web API is designed to store and fetch documents.
This is what my GET method looks like
[HttpGet]
public IActionResult Get(int visitorId, string documentType)
{
var model = _service.GetDocumentByVisitorId(visitorId, documentType);
return Ok(new ApiOkResponse(model));
}
This is what my GetDocumentByVisitorId looks like -
public VisitorDocumentViewModel GetDocumentByVisitorId(int visitorId,
string DocumentType)
{
var visitorDocCollection = _uow.Repository<VisitorDocuments>().GetAll();
var docTypesCollection = _uow.Repository<DocumentType>().GetAll();
var getVisitorDocument = (from visitorDocuments in visitorDocCollection
join documentTypes in docTypesCollection
on visitorDocuments.DocumentTypeId equals documentTypes.DocumentTypeId
where documentTypes.DocumentTypeName == documentType && visitorDocuments.VisitorId == visitorId
select visitorDocuments).FirstOrDefault();
return _mapper.Map<VisitorDocuments, VisitorDocumentViewModel>(getVisitorDocument);
}
VisitorDocumentViewModel exactly points to all the fields on my database.
When I run it locally, it return the desired result
This is what my url looks like -
http://localhost:1316/api/ves/Document?visitorId=123&DocumentType=Photograph
I have hosted my service and when I try to fetch the result, it doesn't return anything. Says page not found.
This is what my hosted url looks like -
http://192.xxx.xxx.xx:9045/api/ves/Document?visitorId=123&DocumentType=Passport
Browser says -
"Failed to load resource: the server responded with a status of 404
(Not Found)"
The same works on my local. Am I missing something?
Is more information needed?
I was trying to call the Put method through Postman and always getting error: "405 Method Not Allow" and "Message": "The requested resource does not support http method 'PUT'."
I'm using DocumentDB and C#. Here is my code:
[Route("multilanguage/Resources/{id}/{Language}")]
[HttpPut]
public async Task<IHttpActionResult> UpdateResource(string Id, string Language, string text)
{
client = new DocumentClient(new Uri(EndPoint), AuthKey);
var collectionLink = UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId);
var query = new SqlQuerySpec("SELECT * FROM MultiLanguage as m where m.id = #pmId",
new SqlParameterCollection(new SqlParameter[] { new SqlParameter { Name = "#pmId", Value = Id } }));
Document doc = client.CreateDocumentQuery<Document>(
collectionLink, query).AsEnumerable().FirstOrDefault();
List<Models.Translations> d = doc.GetPropertyValue<List<Models.Translations>>("Translations");
Models.Translations temp = d.Find(p => p.Language == Language);
temp.Content = text;
temp.LastModified = DateTimeOffset.Now;
temp.ModifiedBy = "admin";
doc.SetPropertyValue("Translations", d);
Document updated = await client.ReplaceDocumentAsync(doc);
return Ok();
}
When I call the Put method throught Postman, I call "http://localhost:XXXX/multilanguage/resources/2/En". "2" and "En" are the first two parameters in my code. And I also specify the "text" parameter value in the Postman request Body with x-www-form-urlencoded type: key = text, value = Test! This put method suppose to update the temp.Content value to "Test!". However, it always failed with the error I mentioned above.
Did I miss anything here?
The 405 error when performing a PUT request to web api is a well known topic. You can find many solutions in this or this SO question.
And for the design of you controller:
PUT are designed to have a body, just like POST and in your case
you should send all parameters in the body instead.
You should create a class which contains the objects you want to send to the server:
public class resourceClass
{
public string Id { get; set; }
public string Language { get; set; }
public string text { get; set; }
}
Then specify the route without the attribute routing and get the object from the request body
[Route("multilanguage/Resources/PutResource")]
[HttpPut]
public async Task<IHttpActionResult> UpdateResource([FromBody] resourceClass obj)
{
client = new DocumentClient(new Uri(EndPoint), AuthKey);
var collectionLink = UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId);
var query = new SqlQuerySpec("SELECT * FROM MultiLanguage as m where m.id = #pmId",
new SqlParameterCollection(new SqlParameter[] { new SqlParameter { Name = "#pmId", Value = Id } }));
Document doc = client.CreateDocumentQuery<Document>(
collectionLink, query).AsEnumerable().FirstOrDefault();
List<Models.Translations> d = doc.GetPropertyValue<List<Models.Translations>>("Translations");
Models.Translations temp = d.Find(p => p.Language == Language);
temp.Content = text;
temp.LastModified = DateTimeOffset.Now;
temp.ModifiedBy = "admin";
doc.SetPropertyValue("Translations", d);
Document updated = await client.ReplaceDocumentAsync(doc);
return Ok();
}
From the client you could add an object to the PUT request of Content-Type application/json like this
var data = {
Id: clientId,
Language: clientLanguage,
text: clientText
};
Don't forget to stringify the json when adding it to the http request
data: JSON.stringify(data),
The PUT controller will then be reached at "http://localhost:XXXX/multilanguage/resources/putresource".
Check the URL for which you are posting the data, in my case the URL was incorrect because of which I got these errors, also verify that in Body you should select raw and change the Text to JSON if you are passing a JSON as a data.
I created a RESTful api in Visual Studio with the following Controller:
[RoutePrefix("api/json")]
public class JsonController : ApiController
{
[Route("person")]
public string GetPerson()
{
Person person = new Person(0, "John Doe", 99);
JavaScriptSerializer serialize = new JavaScriptSerializer();
return serialize.Serialize(person);
}
}
When I navigate to the api through the browser I get this result:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">{"Id":0,"Name":"John Doe","Age":99}</string>
In my Swift code I´m trying to get this result and parse it to my textboxes with the following code:
var url = "THE URL TO MY SITE"
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
if (jsonResult != nil) {
println(jsonResult)
// process jsonResult
//self.txtStringiFiedText.text = jsonResult["Name"] as NSString
} else {
println(error)
}
})
When I´m running this I get this error:
0x0000000000000000
But when I for example test this API:
http://jsonplaceholder.typicode.com/posts/1 it works and I get the data provided in the JSON.
So there has to be something wrong with my RESTful API Controller method. Anyone has an idea of what it could be?
Appreciate help.
Rather than returning JSON, your API is returning a string that has been serialized as XML. You need to
Just return a Person -- it get serialized for you.
Make sure a JSON formatter is configured: http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization. (It should be by default.)
I am using Azure Mobile Services (following the standard Azure TodoItems tutorial), and the most basic GET method that they provide is:
public IQueryable<MyModel> GetAllMyInfo()
{
return Query();
}
This works, but I am trying to extend it so that the method will only return MyModel data for an authenticated user (identified by the X-ZUMO-AUTH authentication header standard for Mobile Service API calls). So I modified the code for:
public IQueryable<MyModel> GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
var ownerId = currentUser.Id;
return Query().Where(s => s.OwnerId == ownerId);
}
This also works when a valid auth token is passed. However, if an invalid auth header is passed, then the currentUser is null, and the query fails (obviously). So I am trying to check for null and return a BadRequest or a 403 HTTP code. Yet a simple `return BadRequest("Invalid authentication") gives a compilation error:
public IQueryable<MyModel> GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
if(currentUser == null) {
return BadRequest("Database has already been created."); // This line gives a compilation error saying I need a cast.
}
var ownerId = currentUser.Id;
return Query().Where(s => s.OwnerId == ownerId);
}
Does anyone know how to check for a valid authentication token and return a 403 on this method (which wants an IQueryable return type?
You can use the [AuthorizeLevel] attribute on this method to indicate that a valid token must be present in order for the method to be invoked. It will return a 401 if not.
So your full method would be:
[AuthorizeLevel(AuthorizationLevel.User)]
public IQueryable<MyModel> GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
var ownerId = currentUser.Id;
return Query().Where(s => s.OwnerId == ownerId);
}
Please note that for the Azure Mobile Apps SDK (not Mobile Services), the above attribute is simply replaced with [Authorize].
I know this is a bit late, but will document here for you and others that may come looking for a similar problem.
(While agreeing with Matt that a 403 could/should be achieved with a [Authorize] attribute, the question is regarding returning a different HttpStatusCode OR IQueryable)
I had a similar scenario where I needed to validate some query parameters and either return my results or a HttpError (in my case I wanted a 404 with content).
I found 2 ways, either keeping the return as IQueryable<T> and throwing a HttpResponseException or changing the return to IHttpActionResult and returning normal with HttpStatusCode or Ok(Data).
I found to prefer the later as throwing an Exception would be breaking the execution while in debug and not a very pleasant development experience.
Option 1 (Preferred)
//Adding Return annotation for API Documentation generation
[ResponseType(typeof(IQueryable<MyModel>))]
public IHttpActionResult GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
if(currentUser == null) {
return BadRequest("Database has already been created.");
}
var ownerId = currentUser.Id;
return Ok(Query().Where(s => s.OwnerId == ownerId));
}
Option 2 (Throwing Exception)
public IQueryable<MyModel> GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
if(currentUser == null) {
throw new HttpResponseException(System.Net.HttpStatusCode.BadRequest)
// Or to add a content message:
throw new HttpResponseException(new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.BadRequest) {
Content = new System.Net.Http.StringContent("Database has already been created.")
});
}
var ownerId = currentUser.Id;
return Query().Where(s => s.OwnerId == ownerId);
}