I have a form that is generated via jquery:
$.get("/api/get/getListItems", function (data) {
var table = "";
table += "<table>";
$.each(data, function (y, z) {
console.log(z);
table += '<tr>';
$.each(this, function (k, v) {
table += '<td><input type="text" name="' + k + '" id="' + k + '" value="' + v + '" /></td>';
});
table += '<td><input type="checkbox" name="selected" id="selected" /></td>';
table += '</tr>';
});
table += '<tr><td><input type="submit" id="submit" name="submit" value="Save To Database" /></td></tr>';
table += '</table>';
$('#form').html(table);
});
and it generates this HTML (10 rows of input fields, 7 columns and 1 checkbox): http://jsfiddle.net/8zpr2fkL/1/
and I am submitting the form when the submit button is clicked:
$("#form").submit(function (event) {
$.post("/api/update/", $("#form").serialize(), alert('success'));
});
Now I am passing the data to my ASP.NET API Controller:
[HttpPost]
public dynamic Post([FromBody]CellModel cells)
{
UpdateClass jobs = new UpdateClass();
return jobs;
}
and here is my CellModel class:
public class CellModel
{
public uint scheduleTaskID { get; set; }
public string task { get; set; }
public string baselineDate { get; set; }
public string scheduledDate { get; set; }
public string actualDate { get; set; }
public string finishedDate { get; set; }
public bool selected { get; set; }
public override string ToString()
{
return scheduleTaskID.ToString();
}
}
My Problem is when I hit submit to submit the data and put a breakpoint on the controller method, cells count is 0, is there something I am missing here? I am trying to pass all the data in the input text to controller. Nothing is getting passed to my controller. What am I doing wrong?
This is data im trying to pass via jquery $('#form').serialize():
scheduleTaskID=194&task=Permit&baselineDate=6%2F23%2F2005+8%3A00%3A00+AM&scheduledDate=6%2F23%2F2005+8%3A00%3A00+AM&actualDate=6%2F23%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=195&task=Office+Files&baselineDate=7%2F13%2F2005+8%3A00%3A00+AM&scheduledDate=7%2F13%2F2005+8%3A00%3A00+AM&actualDate=7%2F13%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=196&task=Foundation&baselineDate=7%2F27%2F2005+8%3A00%3A00+AM&scheduledDate=7%2F27%2F2005+8%3A00%3A00+AM&actualDate=8%2F13%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=197&task=Framing&baselineDate=8%2F5%2F2005+8%3A00%3A00+AM&scheduledDate=8%2F5%2F2005+8%3A00%3A00+AM&actualDate=8%2F23%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=198&task=Finishes+Exterior&baselineDate=8%2F26%2F2005+8%3A00%3A00+AM&scheduledDate=8%2F26%2F2005+8%3A00%3A00+AM&actualDate=9%2F14%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=199&task=Drywall&baselineDate=9%2F2%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F2%2F2005+8%3A00%3A00+AM&actualDate=9%2F16%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=200&task=Flooring&baselineDate=9%2F1%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F1%2F2005+8%3A00%3A00+AM&actualDate=9%2F20%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=201&task=General+Finish&baselineDate=9%2F12%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F12%2F2005+8%3A00%3A00+AM&actualDate=&finishedDate=&scheduleTaskID=202&task=Final+PDI&baselineDate=10%2F11%2F2005+8%3A00%3A00+AM&scheduledDate=10%2F11%2F2005+8%3A00%3A00+AM&actualDate=&finishedDate=&scheduleTaskID=203&task=Permit&baselineDate=4%2F6%2F2005+8%3A00%3A00+AM&scheduledDate=4%2F6%2F2005+8%3A00%3A00+AM&actualDate=4%2F6%2F2005+8%3A00%3A00+AM&finishedDate=
UPDATE
I have changed:
$("#form").submit(function (event) {
$.post("/api/update/", $("#form").serialize(), alert('success'));
});
to
$("#form").submit(function (event) {
var array = [];
$('#form > table > tbody > tr').each(function (elem) {
var item = {};
item.scheduleTaskID = $(this).find("td > #scheduleTaskID").val();
item.task = $(this).find("td > #task").val();
item.baselineDate = $(this).find("td > #baselineDate").val();
item.scheduledDate = $(this).find("td > #scheduledDate").val();
item.actualDate = $(this).find("td > #actualDate").val();
item.finishedDate = $(this).find("td > #finishedDate").val();
item.selected = $(this).find("td > #selected").val();
array.push(item);
});
console.log(JSON.stringify(array));
$.post("/api/update/", JSON.stringify(array), alert('success'), 'json');
});
in my console log my data looks like this:
[{"scheduleTaskID":"203","task":"Permit","baselineDate":"4/6/2005 8:00:00 AM","scheduledDate":"4/6/2005 8:00:00 AM","actualDate":"4/6/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"195","task":"Office Files","baselineDate":"7/13/2005 8:00:00 AM","scheduledDate":"7/13/2005 8:00:00 AM","actualDate":"7/13/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"196","task":"Foundation","baselineDate":"7/27/2005 8:00:00 AM","scheduledDate":"7/27/2005 8:00:00 AM","actualDate":"8/13/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"197","task":"Framing","baselineDate":"8/5/2005 8:00:00 AM","scheduledDate":"8/5/2005 8:00:00 AM","actualDate":"8/23/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"198","task":"Finishes Exterior","baselineDate":"8/26/2005 8:00:00 AM","scheduledDate":"8/26/2005 8:00:00 AM","actualDate":"9/14/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"199","task":"Drywall","baselineDate":"9/2/2005 8:00:00 AM","scheduledDate":"9/2/2005 8:00:00 AM","actualDate":"9/16/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"200","task":"Flooring","baselineDate":"9/1/2005 8:00:00 AM","scheduledDate":"9/1/2005 8:00:00 AM","actualDate":"9/20/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"201","task":"General Finish","baselineDate":"9/12/2005 8:00:00 AM","scheduledDate":"9/12/2005 8:00:00 AM","actualDate":"","finishedDate":"","selected":"on"},{"scheduleTaskID":"202","task":"Final PDI","baselineDate":"10/11/2005 8:00:00 AM","scheduledDate":"10/11/2005 8:00:00 AM","actualDate":"","finishedDate":"","selected":"on"},{"scheduleTaskID":"203","task":"Permit","baselineDate":"4/6/2005 8:00:00 AM","scheduledDate":"4/6/2005 8:00:00 AM","actualDate":"4/6/2005 8:00:00 AM","finishedDate":"","selected":"on"},{}]
and in my ASP.NET API Controller, I changed my method to this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public class UpdateController : ApiController
{
[HttpPost]
public dynamic Post(List<CellModel> cells)
{
UpdateClass jobs = new UpdateClass();
//jobs.PostScheduledTasks(cells);
return cells;
}
}
}
I put a breakpoint at the start of the method Post and when it hits the breakpoint, it says cells Count = 0..I see network call, only if i put a return false after my post call and the response is empty [] Why is the data not passing to my controller, is it because the form is being generated by jquery?
UPDATE
Still no solution, I looked at my network call this AM and the Status Code is 301:
Don't use $.post
use ajax post and set the content type to
"application/json; charset=utf-8"
var data = JSON.stringify(array);
$.ajax({
url:"/api/update/",
type:"POST",
data:data,
contentType:"application/json; charset=utf-8",
dataType:"json",
success: function(data){
console.log(data);
}
});
the problem is that you need to say to the webserver you are sending json and is not possible with $.post
This is really normal, and I have been struggling with this too (and sometimes I still forget), here you can see that you have to use $.ajax
Jquery - How to make $.post() use contentType=application/json?
While you got an alternative approach by #dariogriffo, i want to give you a full solution using your initial approach with $.post.
Your initial approach with form serialization was correct, so the following code is correct:
$("#form").submit(function (event) {
$.post("/api/update/", $("#form").serialize(), alert('success'));
});
However, this wasn't working because your dynamic form is not following the naming conventions for input fields expected by the ASP.NET MVC Default model binder, and as a consequence your serialized form was not something the default model binder was capable of binding to your cells model. That is why you were not getting any cells in the controller when doing a POST.
To clarify what that means, ASP.NET expects each input field that corresponds to a model property to have the following name format if you are posting to a regular MVC 5 Controller:
actionattributename[index].propertyname
If you are posting to a Web API 2 controller it should be:
[index].propertyname
Since your action attribute is named cells and it has a property scheduledTaskID, and you are posting to a WebAPI controller one of your inputs would look like:
<input type="text" name="[0].scheduleTaskID" id="scheduleTaskID" value="194">
There are a couple more rules involved in structuring a form to make it bindable. You can find a nice blog post about it here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
If you followed that form convention you would be able to Post your serialized form to your controller expecting a List<CellModel> cells without having to use the JSON approach, which is much more expensive as suggested in the other answers.
Below is a fiddle with an example form structured correctly by Web API 2 default binder rules:
http://jsfiddle.net/8zpr2fkL/12/
You can try to $.post this form using $.post to your web api controller and it should work like a charm!
I know, this is already solved using .ajax instead of .post. I thought of sharing this , as i have solved this using .post. As mentioned above, since it posts with content type Content-Type:application/x-www-form-urlencoded; charset=UTF-8, parameter cells in post method will contain count = 0.
To solve this, you have to manually capture request object and get post data and then do deserialize and get object as List<CellModel>. I have used all posted code by OP, and just modified post method as shown in following, and it worked.
[HttpPost]
public dynamic Post(List<CellModel> cells)
{
string content = string.Empty;
if (HttpContext.Current.Request.InputStream.CanSeek)
{
HttpContext.Current.Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
using (System.IO.StreamReader reader = new System.IO.StreamReader(HttpContext.Current.Request.InputStream))
{
content = reader.ReadToEnd();
}
if (!string.IsNullOrEmpty(content))
{
// Deserialize and operate over cells.
try
{
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject(content, typeof(List<CellModel>));
}
catch (Exception ex)
{
return ex;
}
}
return cells;
}
Here is what i get while debugging.
Related
I have this FullCalendar portion of code on my page to pull events from an API controller in a Razor Pages project:
var calendar;
document.addEventListener('DOMContentLoaded', function () {
var calendarEl = document.getElementById('calendar');
calendar = new FullCalendar.Calendar(calendarEl, {
plugins: ['dayGrid', 'interaction', 'list', 'timeGrid'],
defaultView: 'dayGridMonth',
customButtons: {
newEventButton: {
text: 'new event',
click: function () {
window.location.assign("Calendars/EditPersonnelEvent/0");
}
}
},
header: {
left: 'prev,next today',
center: 'title',
right: 'newEventButton,dayGridMonth,timeGridWeek,timeGridDay'
},
events: "/api/fetchEvents"
});
calendar.render();
})
and it seems to be working just fine, here's the snip of the fetch:
The problem is, the event fetched doesn't show on the calendar, on any of the views. When I paste that JSON into a hard-coded event, it works fine and I see the event, just not when it's from the GET. I've tried this with eventSources to no avail. I've searched about 30 different answers here and still no luck. The JSON seems to be formatted correctly, it seems to be getting fetched correctly, it's just not showing up. And yes, I'm looking at the correct days ;)
REQUESTED UPDATE:
Here is the "response" data:
and here's the .NET code for this fetch:
[Route("api/fetchEvents")]
[ApiController]
public class FetchEventsController : ControllerBase
{
private readonly IPersonnelEventService _personnelEventService;
public FetchEventsController(IPersonnelEventService personnelEventService)
{
_personnelEventService = personnelEventService;
}
// GET: api/FetchEvents/5
[HttpGet]
public string Get(string start, string end)
{
int currentUserId = User.Identity.GetUserId();
DateTime objStart = DateTime.Parse(start, null, System.Globalization.DateTimeStyles.RoundtripKind);
DateTime objEnd = DateTime.Parse(end, null, System.Globalization.DateTimeStyles.RoundtripKind);
List<Entities.PersonnelEvent> events = new List<Entities.PersonnelEvent>(_personnelEventService.GetPersonnelEventsByUserId(currentUserId, objStart, objEnd));
return JsonConvert.SerializeObject(events.Select(pe => pe.GetEventAsFullCalendarJson()).ToList());
}
}
and here's the code for "GetEventAsFullCalendarJson":
public string GetEventAsFullCalendarJson()
{
var info = new
{
title = Name,
start = StartDate,
end = EndDate
};
return JsonConvert.SerializeObject(info);
}
}
The problem is you are double-serializing your data.
You serialise each event object individually in GetEventAsFullCalendarJson() when you do return JsonConvert.SerializeObject(info);. So at that point you already have a JSON string representing a single event.
But then you combine all these together and serialise the whole thing again when you write return JsonConvert.SerializeObject(events.Select(pe => pe.GetEventAsFullCalendarJson()).ToList()); in the Get() method. This means the already-serialised JSON event strings are serialised again - which is why you've got quote marks round the event object (e.g. "{ ... }" and then escaped quotemarks (\") within it.
The outcome is that to fullCalendar, your data just looks like an array of strings, not an array of event objects.
The fix is simple - remove the serialisation of the individual events. An object/array must be serialised all at once to create a coherent single piece of JSON.
This:
return JsonConvert.SerializeObject(events.Select(pe => {
title = pe.Name,
start = pe.StartDate,
end = pe.EndDate
}).ToList());
would work, I think.
My page sends a form via $.get to an aspnet core action.
$("#submit-form").on("submit", function () {
var form = $("#submit-form");
var valuesToSubmit = form.serialize();
$.get("/MyController/List", valuesToSubmit, function (response) {
....
});
return false;
});
In this form this is a Date field that is in format: dd/mm/yyyy.
The valuesToSubmit variable has this value:
Name=&DateBirth=05%2F08%2F1971&__RequestVerificationToken=CfDJ8DHb24pNxPVIkZwi2Mzh0aTz4ZPyAIDsVSVm7-KxVMiV17Z1Twov88zN3F-JwewrGHF9LWSkdp5eOks7KwTgHWRhkdE7N6vfBHeNviCNV1cQdHdW5zPQgk3EEFPN1Lqe0vBK9ay5vnc0oCYWWPPuYgmQTC65iYTy7-0oc0CskGJpul5eSwuS3hUMer4P6g16Ng
I typed 05/08/1971 but in the controller the date parameter comes as 08/05/1971
My action code:
public async Task<IActionResult> List(string name, DateTime? dateBirth)
Should I change something in the javascript or c# code?
I am sorry for my typos.I am working on proof of concept C# ASP.NET MVC application where I need to pass data between two views when there is no post and get. One view launches a modal dialog and I need communication between them. We are using JQuery.
I have a view called Charges.cshtml with a data grid. The first column of the datagrid may have span element or a link element depending on a
property which will tell whether the charge have single or multiple descriptions. The view looks like below.
If the charge has multiple descriptions user will click the corresponding description link( Description2 in this case ) and a modal dialog will open showing various descriptions like below
Now in this modal dialog user will confirm/select one description. Now I need to close the modal dialog and update the description of selected
charge like below
The hard part here is how to pass data between two views. I am ok to pass data via controller or via javascript.
I tried various ways to pass selected charge from Charges.cshtml to LoadLoanChargeDescriptions method in LoanCharge controller like json serialize, ViewData, ViewBag, TempData and so on but of no use. I can pass simple data types like int, string, float but not whole object. I feel I need to pass CurrentDescription and Descriptions to my controller and from their I need to move to other pieces. I tried to pass List of strings but could not see how to access them in controller since I got count as 0 in my controller. I am able to open popup of multiple descriptions UI ( for now just added Hello text )
Please see below for my code snippets
Charges.cshtml
#model ChargeViewModel
#using (Html.FAFBeginForm())
{
<div>
<table>
<tbody>
<tr >
//.....
<td>
#if(Model.IsMultipleMatch)
{
var loanCharge = Model as ChargeViewModel;
if (loanCharge.IsMultipleMatch == true)
{
//string vm = #Newtonsoft.Json.JsonConvert.SerializeObject(loanCharge);
<span>
<a
onclick="ShowMatchingDescriptions('#Url.Action("LoadLoanChargeDescriptions", "LoanCharge")','', '920','500')">
#loanCharge.Description
</a>
</span>
}
}
else
{
<span>Model.Description</span>
}
</td>
</tr>
</tbody>
</table>
</div>
}
public class ChargeViewModel
{
public string Description {get;set;}
public bool IsMultipleMatch {get;set;}
public List<string> Descriptions {get;set;}
}
public class LoanChargeController
{
public ActionResult LoadLoanChargeDescriptions()
{
// get data here and pass/work on
return View("_PartialMultipleMatchPopup", null);
}
}
In Review.js
function ShowMatchingDescriptions(popUpURL, windowProperties, w, h) {
try {
var left = (screen.width / 2) - (w / 2);
var top = (screen.height / 2) - (h / 2);
var properties = windowProperties + "dialogwidth:" + w + "px;dialogheight:" + h + "px;dialogtop:" + top + "px;dialogleft:" + left + "px;scroll:yes;resizable:no;center:yes;title:Matching Lender’s Fee;";
$.when(
window.showModalDialog(popUpURL, window, properties)
)
.then(function (result) {
var childWindow = result;
});
}
catch (err) {
alert("Error : " + err)
}
}
UPDATE 1
I updated my question and posted more details.
Thanks in advance.
UPDATE 2
Please see for my solution at below link.
MVC pass model between Parent and Child Window
Why don't you use the AJAX for pass the data?
function ChargeViewModel() {
this.Description ='';
this.IsMultipleMatch =false;
}
var chargeViewModel= new ChargeViewModel();
var data = JSON.stringify({ 'chargeViewModel': chargeViewModel });
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: 'html',
type: 'POST',
url: '#Url.Action("LoadLoanChargeDescriptions", "LoanChargeController")',
data: data,
success: function (result) {
//result will be your partial page html output
},
failure: function (response) {
}
});
Then you have to change the controller like this:
public ActionResult LoadLoanChargeDescriptions(ChargeViewModel chargeViewModel)
{
// get data here and pass/work on
return View("_PartialMultipleMatchPopup", null);
}
Let me know you have queries..
I have this OData controller that works fine for GET and Patch method. However, there's a custom GET method that I had to create in order for use to load the data from a different server and copy to the new one from where the OData retrieves the data. When the user "Retrieves" new data, it sends the date as a parameter. Since it's a new claim for the date, I couldn't put the date in the $filter, hence the new GET method.
This is what the GET method looks like:
[ODataRoute("Claims({key})")]
[HttpGet]
[EnableQuery(AllowedQueryOptions= System.Web.OData.Query.AllowedQueryOptions.All)]
public HttpResponseMessage ClaimByDate([FromODataUri] int key)
{
System.Diagnostics.Debug.WriteLine(key);
string date = key.ToString();
DateTime claimDate = DateTime.ParseExact(date, "ddMMyyyy", CultureInfo.InvariantCulture);
DateTime today = DateTime.Today;
if (!ClaimsExistForToday(today))
{
GenerateClaimsList(today, claimDate);
return Request.CreateResponse(HttpStatusCode.OK);
}
return Request.CreateResponse(HttpStatusCode.NotModified);
}
Here's the angularjs controller
vm.retrieve = function () {
if (vm.selectedDate !== null) {
var day = vm.selectedDate.getDate();
var date = (day + "" + (vm.selectedDate.getMonth() + 1) + "" + (vm.selectedDate.getFullYear()));
ClaimService.getClaimsByDate(date)
.then(function (response) { if (response) activate(); })
vm.clear();
}
}
Here's the angular function that's sending the get request:
function getClaimsByDate(date) { //Angularjs service
return $http.get("odata/Claims(" + date + ")")
.then(function (data) {
return true;
});
}
First Issue:
The OData GET method have to have "int" for the parameter. I tried with string and DateTime, but when I send the data with 'string' as paramenter, it won't find the controller at all unless the data was sent as integer. And if I send the date as UTC, I get an error as potentially dangerous and won't execute.
Second Issue:
Sending date as int, it will find the controller if date is sent as 30112015 in the format ddMMyyyy, but it won't find 1112015 or 01112015. It seems like it's only recognizing the date greater than 10. Other than this, everything else works fine including the regular GET method with [EnableQuery].
I found this SO answer Web API and OData- Pass Multiple Parameters which helped me out. I ended up creating a function with the key as parameter. Then it was only a matter of calling the function from Angular.
I am using select2 library for replacing select boxes. I rearranged example 7 that you can find on Select2 library page (scroll down with id
$("#e7").select2 etc...). I made my own generic handler that return serialized json data:
GetData.asxh view :
public class GetData : IHttpHandler
{
public bool IsReusable
{
get
{
return false;
}
}
public class RecipesList
{
public int total { get; set; }
public List<TopRecipeTable> recipes { get; set; }
public RecipesList() { }
public RecipesList(int total, List<TopRecipeTable> recipes)
{
this.total = total;
this.recipes = recipes;
}
}
private string GenerateJsonSerializedObject(int languageId, string orderBy)
{
RecipesList recipeList = new RecipesList(15, DBDataBase.GetTopRecipesByNumberOfRecipes(languageId, 15));
return new JavaScriptSerializer().Serialize(recipeList);
}
public void ProcessRequest(HttpContext context)
{
int languageId;
bool languageParsed = int.TryParse(context.Request["languageId"], out languageId);
string orderBy = (string)context.Request["orderBy"];
if (languageParsed && orderBy != string.Empty)
{enter code here
context.Response.ContentType = "application/json";
var jsonValue = GenerateJsonSerializedObject(languageId, orderBy);
context.Response.Write(jsonValue);
}
}
This generic handler returns the right format of json (I checked it with this URL ). My result (json) is also the same as the one in example on above mentioned page. But after this jquery doesn`t fire anymore.
My script :
$(document).ready(function () {
$("#e8").select2({
placeholder: "Search for a recipe",
//minimumInputLength: 1,
ajax: {
url: "/Handlers/GetData.ashx",
dataType: 'jsonp',
data: function (term, page) {
return {
languageId: 1,
orderBy: "TA"
};
},
results: function (data, page) {
alert(data.total);
var more = (page * 10) < data.total; // whether or not there are more results available
// notice we return the value of more so Select2 knows if more results can be loaded
return { results: data.recipes, more: more };
}
},
formatResult: movieFormatResult, // omitted for brevity, see the source of this page
formatSelection: movieFormatSelection, // omitted for brevity, see the source of this page
dropdownCssClass: "bigdrop", // apply css that makes the dropdown taller
escapeMarkup: function (m) { return m; } // we do not want to escape markup since we are displaying html in results
});
});
I tried to write the same alert(data.total) in the original example and it worked but not in my version. So I have the right json format, the jquery calls my generic handler and also recieved parameters languageId ... and also return the right json format but than nothing. I don't know if I am missing something here, because I am sure that this thing could also work with a generic handler as well. I hope I gave enough information about my problem.
I can also add my result in jquery .ajax error handler :
xhr.status = 200
ajaxOptions = parsererror
horwnError = SyntaxError : invalid label
If this is any helpful information
This question is quite old, so pretty sure you have a solution by now...but:
Remove all of these functions:
formatResult: movieFormatResult
formatSelection: movieFormatSelection
dropdownCssClass: ...
escapeMarkup:....
You did not provide those functions to format your data did you? All of those are only needed if you are making a custom drop down of items.
You are returning data.recipes - that needs to be an array of {Text:"", Id:""} or you need to build it from what you return right there.
First, get it working with just a very basic list with very basic data...then go from there.
Additionally, when you get that working try using WebApi or ServiceStack to handle your data instead of an IHttpHandler.