WebAPI REST - not calling correct controller when using multiple parameters - vb.net

Having a bit of an issue getting the Web API to call the correct handler when I pass parameters with my Get request.
My basic handler is this:
Public Function GetAllASTM05Report() As IEnumerable(Of ASTM05Report)
Return repository.GetAll()
End Function
And that returns all records just fine.
But now I want to add this:
Public Function GetASTM05ReportWithSearch(sortField As String, searchOrder As String, searchField As String, searchValue As String) As IEnumerable(Of ASTM05Report)
Return repository.GetAllWithSearch(0, 25, sortField, searchOrder, searchField, searchValue)
End Function
But when I try this URI:
http://localhost/AdminAPI/api/astm05report?sortField=reportId&sortOrder=ASC&searchField=ReportID&searchValue=rr
I expect it to use GetASTM05ReportWithSearch() but it ends up going to GetAllASTM05Report().
If I remove GetAllASTM05Report() then I get an error: No HTTP resource was found that matches the request URI.
One person supposedly got it working by passing an object like this:
Public Function GetASTM05ReportWithSearch(<FromBody> values As SearchValues)
Return repository.GetAllWithSearch(0, 25, values.sortField, values.searchOrder, values.searchField, values.searchValue)
End Function
But I got an error: Multiple actions were found that match the request
If I remove GetAllASTM05Report(), GetASTM05ReportWithSearch() does fire, but values is nothing.
I have not changed the default routing tables and my client JS does not like the true REST syntax like:
http://localhost/AdminAPI/api/astm05report/reportId/ASC/ReportID/rr
So I do not want to explore solutions which require such routing table mods.
Help! What am I doing wrong?
EDIT: Jon Susiak called it - misnamed parameter. Embarrassing!
Thanks,
Brad

Related

How to get return value from function used in thread in vb. Net

Public function myfn1(byval pRequest as string) as string
Dim param(1) object
param(0)=pRequest
Dim T as new thread(Addresof myfn2)
T. Start(param)
End function
Private function myfn2(byval pReq as string) as string
'////some stuff here////
Return lstrResponse
End function
Here myfn1 is accepting requests from user. Sometimes the requests may be concurrent at a time. So I have used thread in myfn1. Myfn2 is actually processing the request and returning the response. So I am willing to get that response in myfn1 after the thread processed the task. What should I do? Or is there any other way out, Pls suggest
You should look into using the Async/Await structure : https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/concepts/async/
For Doing CPU bound work on a separate thread there are a couple options. I like using Task.Run() doc here: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run?view=netframework-4.8
You can awaitthe task you create and get the result when it's done like:
SomeVariable = Await Task.Run(Function() FunctionName)

Mocking MailController with ActionMailer.net using Moq 3

I'm new to Moq, so any help would be great. I keep getting a null reference error in my code when I'm trying to set up a test. Here is the line of code where I'm getting the error below.
_iMailController.RequesterEmail(model).Deliver();
Here is what my test looks like:
_mockMailController = new Mock<IMailController>();
mockMailController .Setup(x => x.RequesterEmail(new Model())).Returns(**new EmailResult()**);
The bold part is where I'm stuck at. It takes 7 parameters and dont know what to put to fake out the EmailResult.
You are confusing, The Return part will single return values like string, list, bool or Int ect.
So you can easily pass the value which you get in return on the RequesterEmail on the IMailController. So you have to check the which value get retun from the RequesterEmail method.
You may also use the below code as example:
mockMailController .Setup(x => x.RequesterEmail(It.IsAny<Model>())).Returns(**new EmailResult()**);
Refet the below Part too.
It mentioned about how many parameter you passed in the RequesterEmail method. If there is 7 parameters passed on the method then you may have to pass 7 parmeter like bleow
Please look deeply in parameter and return on both codes down here.
And look where i use ModelClass in both below codes.
If the Method have parameters like below:
public void RequesterEmail( string, int, list, EmailClass, someClass, bool, string);
{
return ModelClass;
}
then you may have to write the code as below
mockMailController .Setup(x => x.RequesterEmail(It.IsAny<string>(), It.IsAny<int>(),
It.IsAny<EmailClass>(), It.IsAny<someClass>(), It.IsAny<bool>(),
It.IsAny<string>())).Return(ModelClass)

MVC returns page as a file

I have an mvc4 project and I am getting a weird result. Whenever I sumit a form and fire up a postback, if the entry is correct it redirects me to the success page which is good. But when my input is invalid and it has to return to the same page, to display the error message, it comes up as a downloadable file. Can anybody please tell me what is going on?
<HttpPost()>
Public Function Collection(oColInfo As CollectionInfoVM) As ActionResult
If ModelState.IsValid Then
oColInfo.CollectionDate = DateTime.Now
m_oAppBase.Collection.AddGroupCollection(oColInfo)
Return View("_Success")
Else
ViewData.Add("PaymentTypes", PaymentType.Dictionary.ToSelectList(oColInfo.PaymentType))
ViewData.Add("PaidBy", PaidBy.Dictionary.ToSelectList(oColInfo.PaidBy.ToString()))
Return View(oColInfo)
End If
End Function
EDIT 1 :
I also found out that my controller is returning my view as JSON. That's why IE is asking me if i wanted to download it. Why is my default return type JSON?
EDIT 2 :
The response type is application/json instead of text/html.
EDIT 3 :
It works when I remove the Html.RenderAction("MainMenu", "Menu") from my layout
Controller action looks like this;
Public Function MainMenu() As PartialViewResult
' Let's see if we have an unprocessed turnin from this district
Dim dtDate As Date = DateTime.Now
Dim colDistStatus As List(Of DistrictStatus) = m_oAppBase.TurnIn.GetNextTurnInStatus()
ViewData.Add("DistrictStatus", colDistStatus)
Return PartialView("_MainMenu")
End Function
Why is my default return type JSON?
ActionResult includes JsonResult too.so when you use ActionResult and you post data from ajax ,your default returns Json.
But when my input is invalid and it has to return to the same page
for validate form in client side,you have to use valid method in your script.it validates form in clientside and doesnt post to your action.
JqueryCode:
if ($('form').valid()) {
$.ajax({});
});
Okay, so looking around I found out that there was a partial view on the page with attribute that returns JSON and when I submit the button this get's fired up too and returned to the browser. I removed the HttpPost attribute and it fixed it. sigh

Deserialize object content manually in Web-API OData

When using WCF Data Services Client to communicate with my OData API, I occasionally need to use the
AddRelatedObject method of System.Data.Services.Client.DataServiceContext
This generates a POST to the endpoint that looks like:
http://base_url/odata/Entity(key)/NavigationProperty
The content of the http request is the serialized NavigationProperty entity.
Since a post to this URL is unmapped in a default odata controller, I wrote a new EntitySetRoutingConvention class:
Public Class AddRelatedObjectRoutingConvention
Inherits EntitySetRoutingConvention
Public Overrides Function SelectAction(odataPath As Http.OData.Routing.ODataPath, controllerContext As Http.Controllers.HttpControllerContext, actionMap As ILookup(Of String, Http.Controllers.HttpActionDescriptor)) As String
If controllerContext.Request.Method = Net.Http.HttpMethod.Post Then
If odataPath.PathTemplate = "~/entityset/key/navigation" Then
If actionMap.Contains("AddRelation") Then
Return "AddRelation"
End If
End If
End If
Return Nothing
End Function
End Class
I added this to the default routing conventions list and passed it to the MapODATARoute routine.
In my base controller I implemented AddRelation, and it is called perfectly.
From this I am able to get the odatapath, and parse it to determine the types and keys that are needed.
The problem I am having, is that once I know that my parent entity is a Tenant with a key of 1, and that the NavigationProperty of Users in the Tenant entity is a User entity, I can not figure out how to manually call an odatamediatypeformatter to deserialize the http content into the User entity so that I can then add it to the Tenants Users collection.
I have reviewed the OData source in an effort to find out how to the Web-API pipeline calls and deserializes the entity but have been unable to find the point at which the OData library takes the http content and turns it into an entity.
If anyone has an ideas to point me in the right direction, I will continue researching and update if I figure out more.
UPDATE 06/28/2013
Thanks to RaghuRam, I've been able to get closer. The problem I'm seeing is that the request.getconfiguration().formatters, or odatamediatypeformatters.create both seem to create type specific deserializers.
When I call ReadAsAsync I receive the error:
No MediaTypeFormatter is available to read an object of type 'User' from content with media type 'application/atom+xml'.
As the post shows above, the context of the controller is a Tenant, so I believe the formatters are typed to a Tenant and so can't deserialize the User.
I tried manually creating a formatter, _childDefinition is the EDM Type Reference from the navigation property of the odatapath. In this case a User.
Dim dser As New Formatter.Deserialization.ODataEntityDeserializer(_childDefinition, New Formatter.Deserialization.DefaultODataDeserializerProvider)
Dim ser As New Formatter.Serialization.ODataEntityTypeSerializer(_childDefinition, New Formatter.Serialization.DefaultODataSerializerProvider)
Dim dprovider As New Formatter.Deserialization.DefaultODataDeserializerProvider
dprovider.SetEdmTypeDeserializer(_childDefinition, dser)
Dim sprovider As New Formatter.Serialization.DefaultODataSerializerProvider
sprovider.SetEdmTypeSerializer(_childDefinition, ser)
Dim fmt As New Formatter.ODataMediaTypeFormatter(dprovider, sprovider, New List(Of Microsoft.Data.OData.ODataPayloadKind) From {Microsoft.Data.OData.ODataPayloadKind.Entry})
fmt.SupportedEncodings.Add(System.Text.Encoding.UTF8)
fmt.SupportedEncodings.Add(System.Text.Encoding.Unicode)
fmt.SupportedMediaTypes.Add(Headers.MediaTypeHeaderValue.Parse("application/atom+xml;type=entry"))
fmt.SupportedMediaTypes.Add(New Headers.MediaTypeHeaderValue("application/atom+xml"))
I have then tried:
request.content.ReadAsAsync(of User)(new List(of odatamediatypeformatter) from {fmt})
request.content.ReadAsAsync(of User)(request.getConfiguration().formatters)
request.content.ReadAsAsync(of User)(odatamediatypeformatters.create)
All giving the same error, it seems like I'm missing something obvious.
Thanks!
Steve
Just add a parameter of type User to your AddRelation action and you should be good. Web API would automatically invoke the OData formatter to read the User from the request body and bind it to your action parameter.
You can use this helper method to read OData request body,
private static Task<T> ReadODataContentAsAsync<T>(HttpRequestMessage request)
{
var formatters =
ODataMediaTypeFormatters.Create()
.Select(formatter => formatter.GetPerRequestFormatterInstance(typeof(T), request, request.Content.Headers.ContentType));
return request.Content.ReadAsAsync<T>(formatters);
}
like this,
Customer addedCustomer = ReadODataContentAsAsync<Customer>(Request).Result;

Pass parameter values from JQuery to VB.Net Function

I have here a vb.net function which accepts 2 parameters and the values that will be passed here will be coming from my jquery code. Is it possible to pass the values from jquery to vb.net? I've already read some solutions but they point out that the vb.net method should be a webmethod. In my case, the vb function is not a web method so that strikes that out. Below are some snippets of my code. Hope you could help me on this.
JQuery code
$('#TextBox_PRVNo').keypress(function (event) {
if (event.keyCode == '13') {
//basically, pass values from textbox 1 and textbox 2 to VoucherNotClaimed() method
}
});
VB.Net code
Private Function VoucherNotClaimed(ByVal strVoucherType, ByVal strPRVNo) As Boolean
' TODO: Search in database
Return True
End Function
You don't need a web service to decorate your methods with the WebMethod attribute. If you do it on a regular page, you create a so-called page method. In a nutshell:
Create a public static method in your page, decorated with the WebMethod attribute:
<WebMethod()> _
Public Shared Function VoucherNotClaimed(ByVal strVoucherType, ByVal strPRVNo) As Boolean
' TODO: Search in database
Return True
End Function
Add a ScriptManager to your ASPX page and set its EnablePageMethods property to True. Also, make sure your web.config is set up properly.
Call your method with JavaScript:
var claimed = PageMethods.VoucherNotClaimed(voucherType, prvNo);
You can find a more detailed explanation in the following MSDN article:
Exposing Web Services to Client Script (Section Calling Static Methods in an ASP.NET Web Page)
Note that this is the classic way to do it. With JQuery, it is also possible to call the page method without a ScriptManager; a quick Google search for page method jquery yields a huge amount of blog entries going into every possible detail.