Why is Nancy model binding failing? - nancy

I have a Nancy.SelfHost service that is working just fine for the Get routes, but is failing on the Post route. If fails on the Bind<T>() command in the following route with a "No parameterless constructor defined for this object" error:
Post["/schedule"] = _ =>
{
var schedule = this.Bind<OatiDay[]>();
PostSchedule(schedule);
return HttpStatusCode.Created;
};
Here is the call stack returned with the error:
Nancy.RequestExecutionException: Oh noes! ---> System.MissingMethodException: No parameterless constructor defined for this object.
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at Nancy.Serialization.JsonNet.JsonNetBodyDeserializer.CreateObjectWithBlacklistExcluded(BindingContext context, Object deserializedObject)
at Nancy.Serialization.JsonNet.JsonNetBodyDeserializer.Deserialize(String contentType, Stream bodyStream, BindingContext context)
at Nancy.ModelBinding.DefaultBinder.DeserializeRequestBody(BindingContext context)
at Nancy.ModelBinding.DefaultBinder.Bind(NancyContext context, Type modelType, Object instance, BindingConfig configuration, String[] blackList)
at Nancy.ModelBinding.DynamicModelBinderAdapter.TryConvert(ConvertBinder binder, Object& result)
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at Nancy.ModelBinding.ModuleExtensions.Bind[TModel](INancyModule module)
at TSID.Scada.Nancy.ScheduleService.<.ctor>b__2(Object _) in p:\TSIDDev\TSID.Scada\TSID.Scada.Nancy\ScheduleService.cs:line 24
at CallSite.Target(Closure , CallSite , Func`2 , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
at Nancy.Routing.Route.<>c__DisplayClass4.<Wrap>b__3(Object parameters, CancellationToken context)
--- End of inner exception stack trace ---
at Nancy.NancyEngine.InvokeOnErrorHook(NancyContext context, ErrorPipeline pipeline, Exception ex)
It looks as though something is going wrong with the deserializer, but I can't tell what is being created. The post code is passing all its tests on the server using the Nancy Browser, so something must be wrong with the request. But I can't figure out what it is. The OatiDay class is just a poco object.
public class OatiDay
{
[BsonId]
public string Id { get; set; }
[BsonDateTimeOptions(DateOnly = true, Kind = DateTimeKind.Local)]
public DateTime Date { get; set; }
public String Facility { get; set; }
public Production OnPeak { get; set; }
public Production OffPeak { get; set; }
public class Production
{
public Int32 ScheduleForDay { get; set; }
public double? ActualForDay { get; set; }
public Int32 ScheduledToDate { get; set; }
public double? ActualToDate { get; set; }
}
}
Here is the request sent from an Angular $http service:
POST http://buckhorn1:7000/schedule HTTP/1.1
Host: buckhorn1:7000
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Referer: http://buckhorn1:7203/schedule
Content-Length: 793
Origin: http://buckhorn1:7203
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
[{"id":"20150712","date":"2015-07-12T00:00:00Z","facility":"Watson","onPeak":{"scheduleForDay":0,"actualForDay":6.56,"scheduledToDate":77,"actualToDate":92.61},"offPeak":{"scheduleForDay":12,"actualForDay":4.26,"scheduledToDate":71,"actualToDate":64.97},"hasPeak":false},{"id":"20150713","date":"2015-07-13T00:00:00Z","facility":"Watson","onPeak":{"scheduleForDay":8,"actualForDay":8,"scheduledToDate":85,"actualToDate":100.61},"offPeak":{"scheduleForDay":4,"actualForDay":4,"scheduledToDate":75,"actualToDate":68.97},"hasPeak":true},{"id":"","date":"2015-07-14T00:00:00.000Z","facility":"Watson","hasPeak":true,"onPeak":{"scheduleForDay":9,"scheduledToDate":94,"actualForDay":9,"actualToDate":109.61},"offPeak":{"scheduleForDay":5,"scheduledToDate":80,"actualForDay":5,"actualToDate":73.97}}]
Can anyone tell me how to troubleshoot this?

I could not get the Nancy model-binding to work. I suspected it had something to do with the deserialization of the camel cased body. I replaced this:
var schedule = this.Bind<OatiDay[]>();
with this:
var reader = new StreamReader(this.Request.Body);
string text = reader.ReadToEnd();
var schedule = JsonConvert.DeserializeObject<OatiDay[]>(text);
and my service is working.

Had the same problem. This is actually Newtonsoft.Json problem.
One of these can help:
1) Changing OatiDay[] to List. This actually was my solution.
2) Add wrapper class with property if possible { OatiDay[] OatiDays { get; set; } }
3) Direct Json.Net Deserialization (pthalacker answer)
4) Implement custom model binder Nancy.ModelBinding.IModelBinder.

Related

How can I get data after passing parameter of SQL Server procedure in ASP.NET Core Web API?

I want to get data from a SQL Server database using a procedure passing some parameters. Is this the right way to do this? The code shown here is not working. Is there any way to get data ?
I want to call
Controller:
[Route("api/[controller]")]
[ApiController]
public class ReportController : ControllerBase
{
public IConfiguration Configuration { get; }
private readonly DatabaseContext _context;
public ReportController(IConfiguration configuration, DatabaseContext context)
{
Configuration = configuration;
_context = context;
}
[Route("AllCollectionReport")]
[HttpGet]
public IActionResult CollectionReport()
{
DataTable dt = new DataTable();
string imsConn = Configuration["ConnectionStrings:IMSConnection"];
using (SqlConnection con = new SqlConnection(imsConn))
{
string query = "KK_SP_VIEWREPO"; //<-- Here is the procedure
using (SqlCommand cmd = new SqlCommand(query))
{
cmd.Connection = con;
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
sda.Fill(dt);
}
}
}
return Ok(dt);
}
}
SQL query:
CREATE PROCEDURE KK_SP_VIEWREPO
AS
BEGIN
SELECT *
FROM KK_SalesEntry
END
This is the error what I got after get calling the method in Postman - is anything wrong with this code?
Get: https://localhost:44372/api/Report/AllCollectionReport
Error: System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 maxDepth)
at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Host: localhost:44372
User-Agent: PostmanRuntime/7.26.5
Postman-Token: d65e0dd3-3c9d-4066-ba8f-db7940509c60
Help me.. :-(
You cannot return DataTable. It is not serializable. You can return Strongly Typed object.
something like this may help
List<Object> objList = new List<Object>();
using (SqlCommand cmd = new SqlCommand(query))
{
cmd.Connection = con;
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read()) {
objList.Add(new {
UserId = reader[0].ToString()
UserName = raeder[1].ToString()
});
}
}
}
return objList;

Postman gets data from api but .net core 2.2 app not

I can't retreive response from backend API in .NET CORE 2.2 app. but in Postman
I can retreive data. In .NET CORE 2.2 app throw an error:
An unhandled exception occurred while processing the request.
IOException: The server returned an invalid or unrecognized response.
System.Net.Http.HttpConnection.FillAsync()
HttpRequestException: Error while copying content to a stream.
System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
HttpRequestException: Error while copying content to a stream.
System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task<HttpResponseMessage> sendTask, HttpRequestMessage request, CancellationTokenSource cts, bool disposeCts)
Test.Controllers.HomeController.Login(AuthUser authUser) in HomeController.cs
+
var response = await client.PostAsync("http://192.168.43.96:9890/api/login", content);
Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor+TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I've tried to change connection value to close, but it didn't work out.
In C# I have following code:
string response = await "http://192.168.43.96:9890/api/login".PostJsonAsync(new { login = "admin", password = "admin" }).ReceiveJson();
I do the request in C# with fluent HTTP. I've tested httpClient and it didn't work out.
Backend is written in C.
The response which produce backend is below:
HTTP/1.1 200 OK
Content-Length: 262
Connection: keep-alive
Content-Type: application/json
Server: Simple HTTP with C server
Date: Sun Jun 9 19:03:06 2019
{
"data": [{
"id": "1",
"login": "admin",
"first_name": "Main",
"last_name": "Admin",
"email": "main.admin#myhelpdesk.com",
"role_id": "1"
}],
"token": {
"value": "c509fe9566db8302ef11d78974579bc9a825d617c44d78bfeda959d3a8d9f163"
}
}
Finally I want to make it happen in this .NET CORE 2.2 APP.
Please help.
You could try to create the entities in your client side like :
public class Datum
{
public string id { get; set; }
public string login { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public string role_id { get; set; }
}
public class Token
{
public string value { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
public Token token { get; set; }
}
And use HttpClient to send request to your server side , read response and deserialize Object :
try
{
using (HttpClient client = new HttpClient())
{
var content = new StringContent(jsonInString, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
if (response != null)
{
var jsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<RootObject>(jsonString);
}
}
}
catch (Exception ex)
{
}

AngularJS + Spring3.2 415 Unsupported Media Type error

I am using AngualrJS and Spring MVC3.2. I am trying to post simple object shown below to the server but I am getting '415 Unspported Media Type error'.
#Entity
#Table(name="Question")
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long id = 0;
private String statement;
private int frequency;
private int difficulty;
private String comment;
private String reference;
#Temporal(TemporalType.TIMESTAMP)
protected Date regTime;
#Temporal(TemporalType.TIMESTAMP)
protected Date updTime;
#OneToMany(mappedBy="question", fetch=FetchType.EAGER)
#NotFound(action=NotFoundAction.IGNORE)
private List<Answer> answers = new ArrayList<Answer>();
//Getters and setters
}
#Entity
#Table(name="Answer")
public class Answer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long id = 0;
private String answer;
#Column(name="correct", columnDefinition="INT(1)")
private boolean correct;
#ManyToOne
#JoinColumn(name="questionId", referencedColumnName="id")
#NotFound(action=NotFoundAction.IGNORE)
#JsonIgnore
private Question question;
//Getters and setters
}
#Controller
#RequestMapping("/question")
public class QuestionController {
#RequestMapping(method=RequestMethod.POST)
public #ResponseBody HttpResult submit(#RequestBody Question question) {
HttpResult result = new HttpResult();
//Do something here
return result;
}
}
services.js
$scope.submit = function(entity){
$scope.formshow = false;
var obj = angular.copy(entity);
Question.save(obj, function(data){
if (data.ok == true){
Question.add('success', 'Data has been saved successfully.');
$scope.loadData();
} else {
Question.add('danger', data.msg);
}
});
};
JSON in the JSP page
{
"id":0,
"answers":[
{
"id":0,
"answer":"a",
"correct":false
},
{
"id":0,
"answer":"b",
"correct":true
},
{}
],
"statement":"test question",
"frequency":0,
"difficulty":0,
"comment":"comment",
"reference":"ref"
}
Http header in firebug
Response Headers
Content-Length 1048
Content-Type text/html;charset=utf-8
Date Mon, 05 May 2014 12:29:56 GMT
Server Apache-Coyote/1.1
Request Headers
Accept application/json, text/plain, */*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
I know that 415 error means that http header content-type is wrong or request data format is invalid.
I have tried to change http header type forcefully but I could not change it. How do I fix this?
Your answer would be appreciated.
Indeed the default Content-Type is application/json, however you're sending text/html. Nothing new to you so far, I know.
Since version 1.1.1 (if I'm not mistaken) you can enforce the content type at the $resource definition.
Can you try to define your $resource like this:
var Question = $resource('your/resource/url',{your params if any, otherwise send this as an empty object},{
post: {
method:'POST',
isArray: false,
headers: {'Content-Type': 'application/json;charset=UTF-8'}
}
} )
then, instead of Question.save(), use Question.post(...). I have created the post method just so you don't lose the save() default behavior...but you could configure the save method exactly like I've configured the post method.
P.S.: This code is untested.

Nancy.Testing exception thrown when testing POST route with Json content

I'm attempting to write tests for my Nancy module, and it's not going too well so far.
Attempting to test two separate actions, one GET which is working just fine and a POST with application/json content in the request.
I'm slightly stabbing in the dark as to how the test for the POST should be written, but have come up with the following:
using NUnit.Framework;
[TestFixture]
public class MyModuleTests
{
Browser browser;
[SetUp]
public void SetUp()
{
browser = new Browser(with =>
{
with.Module<MyModule>();
with.EnableAutoRegistration();
});
}
[Test]
public void Can_Get_View()
{
// When
var result = browser.Get("/View", with => with.HttpRequest());
// Then
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode); // this works
}
[Test]
public void Can_Post_to_EvaluateDocument()
{
var testData = new List<FakeInputValue>(){new FakeInputValue()
{
Name = "a",
Value = 0.35
}};
// When
var result = browser.Post("/Evaluate", with => //the exception is thrown on this line
{
with.HttpRequest();
with.JsonBody<IList<FakeInputValue>>(testData);
});
// Then
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}
}
class FakeInputValue
{
public string Name { get; set; }
public double Value { get; set; }
}
Unfortunately this throws the following juicy error
1) Test Error : MyModuleTests.Can_Post_to_EvaluateDocument
System.Exception : ConfigurableBootstrapper Exception
----> Nancy.RequestExecutionException : Oh noes!
----> System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> System.MissingMethodException : No parameterless constructor defined for this object.
at Nancy.Testing.PassThroughStatusCodeHandler.Handle(HttpStatusCode statusCode, NancyContext context)
at Nancy.NancyEngine.CheckStatusCodeHandler(NancyContext context)
at Nancy.NancyEngine.<>c__DisplayClass8.<HandleRequestInternal>b__6(Task`1 completeTask)
at Nancy.NancyEngine.HandleRequestInternal(Request request, Func`2 preRequest)
at Nancy.NancyEngine.HandleRequest(Request request, Func`2 preRequest)
at Nancy.Testing.Browser.HandleRequest(String method, String path, Action`1 browserContext)
at MyModuleTests.Can_Post_to_EvaluateDocument() in line 49
--RequestExecutionException
at Nancy.NancyEngine.InvokeOnErrorHook(NancyContext context, ErrorPipeline pipeline, Exception ex)
--TargetInvocationException
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Nancy.ModelBinding.DefaultBodyDeserializers.JsonBodyDeserializer.Deserialize(String contentType, Stream bodyStream, BindingContext context)
at Nancy.ModelBinding.DefaultBinder.Bind(NancyContext context, Type modelType, Object instance, BindingConfig configuration, String[] blackList)
at Nancy.ModelBinding.DynamicModelBinderAdapter.TryConvert(ConvertBinder binder, Object& result)
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at MyModule.<.ctor>b__9(Object parameters)
at CallSite.Target(Closure , CallSite , Func`2 , Object )
at Nancy.Routing.Route.<>c__DisplayClass4.<Wrap>b__3(Object parameters, CancellationToken context)
--MissingMethodException
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at Nancy.Json.JavaScriptSerializer.ConvertToObject(IDictionary`2 dict, Type type)
at Nancy.Json.JavaScriptSerializer.ConvertToList(ArrayList col, Type type)
at Nancy.Json.JavaScriptSerializer.ConvertToType[T](Object obj)
Any help as to (a) how I might better test POST routes with application/json content in Nancy or (b) resolve this particular error!
edit 1
My module is as follows:
public class MyModule : NancyModule
{
public MyModule()
{
Get["/View"] = parameters =>
{
return View["myView"];
};
Post["/Evaluate"] = parameters =>
{
this.inputs = this.Bind<List<InputValue>>();
var evaluator = new Evaluator(inputs);
return Response.AsJson<List<Evaluation>>(evaluator.Evaluate());
};
}
}
After a lot of debugging and frustrated outputting to Console, I've tracked down the cause of the bug. The issue was with the lack of public setters in my InputValue class.
The buggy class was written as so:
public class InputValue
{
private readonly string _name;
private readonly double _value;
public InputValue(string inputName, double inputValue)
{
this._name = inputName;
this._value = inputValue;
}
public string Name
{
get
{
return this._name;
}
}
public double Value
{
get
{
return this._value;
}
}
}
I resolved the issue quite simply by allowing the properties to be set, as so:
public class InputValue
{
public string Name
{
get;
set;
}
public double Value
{
get;
set;
}
}

WCF Dictionary<string, object> serialization

I have a service that has a method like this
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService
{
[OperationContract]
public object MyMethod(string param1, string param2, object[] myarray)
{
//do stuff
return result;
}
}
I call my method from my code like this:
public Dictionary<string, object> MyDictionary{ get; set; }
serv.MyMethodCompleted += new EventHandler<MyServiceReference.MyMethodCompletedEventArgs>(serv_MyMethodCompleted);
serv.MyMethodAsync("param1","param2", new ObservableCollection<object>(){MyDictionary});
void serv_MyMethodCompleted(object sender, MyServiceReference.MyMethodCompletedEventArgs e)
{
//Happy happy joy joy
}
Everithing craches with this error:
There was an error while trying to
serialize parameter :myarray. The
InnerException message was 'Type
'System.Collections.Generic.Dictionary`2[[System.String,
mscorlib, Version=2.0.5.0,
Culture=neutral,
PublicKeyToken=7cec85d7bea7798e],[System.Object,
mscorlib, Version=2.0.5.0,
Culture=neutral,
PublicKeyToken=7cec85d7bea7798e]]'
with data contract name
'ArrayOfKeyValueOfstringanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays'
is not expected. Add any types not
known statically to the list of known
types - for example, by using the
KnownTypeAttribute attribute or by
adding them to the list of known types
passed to DataContractSerializer.'.
Please see InnerException for more
details.
public System.IAsyncResult BeginCallMethod(string param1, string param2, System.Collections.ObjectModel.ObservableCollection<object> myarray, System.AsyncCallback callback, object asyncState) {
object[] _args = new object[3];
_args[0] = param1;
_args[1] = param2;
_args[2] = myarray;
System.IAsyncResult _result = base.BeginInvoke("MyMethod", _args, callback, asyncState); <--here it craches
return _result;
}
what did I did wrong? how can I fix this?
The myArray parameter and the return value needs to be a strongly typed and attributed with DataContract and DataMember attributes. The myArray should be collection like IEnumerable<Item> that can be serialized:
[DataContract]
class Item
{
[DataMember]
public string Name {get;set;}
[DataMember]
public double Cost {get;set;}
}

Resources