I am using dot net core web api and I was trying to implement DI. I came to notice that , the moment you declare parameterised constructor the api wont work.
Sample:
[Route("api/[controller]")]
public class ValuesController : Controller
{
public ValuesController()
{
}
public ValuesController(string abc)
{
abc = "123";
}
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
I dont know what exactly went wrong...
Seems like I just had to configure DI, since proper DI was not configured it was not able to figure out the purpose of the constructor.
Related
I'm passing around classes that derive from a common class. I'm finding that, despite passing deserialization valid data, the hub does not respect the TypeNameHandling and completely ignores the $type of the JSON. It deserializes to the base class regardless of what I try.
I event went and took the JSON that I was sending to the hub, pasted it into the hub code as a string, then used JsonConvert.Deserialize to see what would happen and it correctly deserialized to my derived object.
In my startup, I have
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
};
I wasn't sure if this was actually being used, so I had created a test JSON converter and put a debug on the CanRead property (which I had return a static false). That got hit. This also allowed my string deserialization to work.
So what is the hub doing differently that everything seems to work except the hub?
despite passing deserialization valid data, the hub does not respect the TypeNameHandling and completely ignores the $type of the JSON. It deserializes to the base class regardless of what I try.
I did a test with following code snippet, which work for me, you can refer to it.
In Startup:
services.AddSignalR().AddJsonProtocol(options => {
options.PayloadSerializerSettings = new Newtonsoft.Json.JsonSerializerSettings
{
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto
};
});
Hub method:
public async Task SendMessage1(Business mes)
{
//code logic here
//...
}
Classes:
public abstract class Business
{
public string Name { get; set; }
}
public class Hotel : Business
{
public int Stars { get; set; }
}
On client, send following JSON data to above hub method:
var ht = { "$type": "MyNamespaceHere.Hotel, NotesRTMSignalR", "Stars": 4, "Name": "Hudson Hotel" };
Test Result:
Currently I am working on a mini project where I am designing a static website hosted in S3. There is an 'Upload' page on which users will enter name, email and mobile no and files and click on 'Upload' button to invoke the API url endpoint. I have created API gateway url endpoint "https://myAPIName.execute-api.ap-region-1.amazonaws.com/Testing/TestinLambda2" on which I am invoking a post request using XMLHTTPRequest and sending it like this -
xhttp.open("POST", "https://myAPIName.execute-api.ap-region-1.amazonaws.com/Testing/TestinLambda2", true);
xhttp.send(JSON.stringify({Name:$('#Name').val(),Email:$('#email').val(),MobileNo:$('#mno').val()}));
I am sending the data as JSON input to aws lambda Java function.
I have not done any body mapping settings in AWS API gateway.
Back in AWS side, I am using AWS Lambda Java function using POJO. Below are my classes which I got from AWS lambda documentation -
My Lambda function
package com.amazonaws.lambda.demo;
import java.util.Map;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
public class FirstLambda implements RequestHandler<InputClass, OutputClass> {
#Override
public OutputClass handleRequest(InputClass input, Context context) {
String greetingString = String.format("Hello %s, %s , %s.", input.getName(), input.getEmail(), input.getMobile());
//String greetingString = String.format("Hello");
return new OutputClass(greetingString);
}
}
My InputClass
package com.amazonaws.lambda.demo;
public class InputClass {
String Name;
String Email;
String MobileNo;
public String getName(){
return this.Name;
}
public String getEmail(){
return this.Email;
}
public String getMobile(){
return this.MobileNo;
}
public void setName(String Name){
this.Name = Name;
}
public void setEmail(String Email){
this.Email = Email;
}
public void setMobile(String Mobile){
this.MobileNo = Mobile;
}
public InputClass(){
}
public InputClass(String Name, String Email, String Mobile){
this.Name = Name;
this.Email = Email;
this.MobileNo = Mobile;
}
}
My OutputClass
public class OutputClass {
String greetings;
public String getStrings()
{
return greetings;
}
public void setString()
{
this.greetings = greetings;
}
public OutputClass(String greetings)
{
this.greetings = greetings;
}
public OutputClass()
{
}
}
When I click on the 'Upload' button I get the value on my screen as -
{"strings":"Hello null, null , null."}
This is the same value I get when I test the POST method in API gateway using 'Test' option.
If someone can point out what I am missing here, I would really appreciate.
Thank you very much!
The reason why Gerards attempt in recreating the issue didn't work is because he tried this using test event rather than through the apigateway.
What is happening here is that when you are invoking the lambda through the gateway the whole json you send is encapsulated inside another object, which has other details such as pathparameters and other related details.
For testing this out you can create a new POJO and have your InputClass as a member in it. Change lambda paramter to new POJO and invoke lambda through the api gateway again.
This will give you the data you need.
I tested this with the classes you provided using Lambda test event's instead of API Gateway for simplicity, the fix should carry over to your JavaScript as well.
It seems that no matter how you name the class variables in your code, the parameters in the JSON must follow the names your getters/setters. Simply correcting the properties in your code should fix it. This makes sense because your class variables are not accessible from outside the package. So you have to follow the names of the mutator methods.
xhttp.open("POST", "https://myAPIName.execute-api.ap-region-1.amazonaws.com/Testing/TestinLambda2", true);
xhttp.send(JSON.stringify({name: $('#Name').val(), email: $('#email').val(), mobile: $('#mno').val()}));
The following payload:
{
"Name": "Gerard",
"Email": "abc#123.com",
"MobileNo": "8675309"
}
Generates
{"strings":"Hello null, null , null."}
While this payload
{
"name": "Gerard",
"email": "abc#123.com",
"mobile": "8675309"
}
Generated the expected response of:
{"strings": "Hello Gerard, abc#123.com , "8675309"."}
If your AWS Lambda is behind an API Gateway, the gateway will transform the incoming payload and pass it to the AWS Lambda in a different format (that you might expect).
It adds some metadata about the request (e.g. headers) and wraps everything in a JSON with the following format:
{
"headers": {}
"body": ""
...
}
This JSON is passed to your Java AWS Lambda function. You can take a look at this by temporarily adjust your RequestHandler with the following signature:
public class FirstLambda implements RequestHandler<Map<String, Object>, OutputClass> {
#Override
public OutputClass handleRequest(Map<String, Object> input, Context context) {
input.forEach((key, value) -> System.out.println(key + ":" + value);
return new OutputClass("");
}
}
Whenever you use the AWS Console and send a test event with a simple payload like
{
"Name": "Duke",
"Email": "mail#whatever.io"
}
it does not reflect the payload you receive when you invoke your Lambda using the API Gateway and e.g. curl or Postman.
So in your case, you should use e.g. Jackson or GSON to serialize the String inside the body field of the payload to your POJO.
If you don't want to work with a generic Map, you can also include
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>3.1.0</version>
</dependency>
to your project and use the APIGatewayProxyRequestEvent and APIGatewayProxyResponseEvent wrapper classes and access headers, body, etc.
public class FirstLambda implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
#Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEventinput, Context context) {
System.out.println(input.getBody());
// e.g. use the ObjectMapper from Jackson to parse the String body to your POJO
APIGatewayProxyResponseEvent result = new APIGatewayProxyResponseEvent();
result.setStatusCode(200);
result.setBody(objectMapper.writeValueAsString(new OutputClass(""));
return result;
}
}
Another solution would be to adjust the way the API Gateway passes data to your Lambda function, as explained here
I am making a framework for making fractals in processing, however, I need to use functions as parameters for a constructor of a class.
Something like:
class Fractal {
String name;
void initialize;
Fractal(String Name, void setup) {
...
}
}
I'm going to guess you're coming from a JavaScript background?
Traditionally, Java didn't really have a way to do this. Instead you'd pass an anonymous instance of an interface, like this:
interface Runner{
public void run();
}
class Fractal {
String name;
Runner initialize;
Fractal(String name, Runner setup) {
...
}
}
Runner r = new Runner(){
public void run(){
// whatever
}
}
Fractal fractal = new Fractal("name here", r);
Note that Java provides a Runnable interface that you can use instead of creating your own, but I wanted to spell it out here to make it more obvious.
As of Java 8, you can pass a reference to a function as a parameter. This is called a lambda function. Googling "Java lambda function" will return a ton of results.
From this answer:
public void pass() {
run(()-> System.out.println("Hello world"));
}
public void run(Runnable function) {
function.run();
}
Depending on how you're using Processing, you might be stuck with the first approach though, since I don't think the Processing editor supports Java 8 yet.
I need to replace the DateTime serialization for JSON in WCF REST Self Hosted service. Right now, I'm using something like the following code to do it, but it's definitely not the way to go since it requires manipulating each class.
[DataContract]
public class Test
{
[IgnoreDataMember]
public DateTime StartDate;
[DataMember(Name = "StartDate")]
public string StartDateStr
{
get { return DateUtil.DateToStr(StartDate); }
set { StartDate = DateTime.Parse(value); }
}
}
where my utility function DateUtil.DateToStr does all the formatting work.
Is there any easy way to do it without having to touch the attributes on my classes which have the DataContract attribute? Ideally, there would be no attributes, but a couple of lines of code in my configuration to replace the serializer with one where I've overridden DateTime serialization.
Everything that I've found looks like I have to replace huge pieces of the pipeline.
This article doesn't appear to apply because in I'm using WebServiceHost not HttpServiceHost, which not part of the 4.5.1 Framework.
JSON.NET Serializer for WCF REST Services
By default WCF uses DataContractJsonSerializer to serialize data into JSON. Unfortunatelly date from this serializer is in very difficult format to parse by human brain.
"DateTime": "\/Date(1535481994306+0200)\/"
To override this behavior we need to write custom IDispatchMessageFormatter. This class will receive all data which should be returned to requester and change it according to our needs.
To make it happen to the operations in the endpoint add custom formatter - ClientJsonDateFormatter:
ServiceHost host=new ServiceHost(typeof(CustomService));
host.AddServiceEndpoint(typeof(ICustomContract), new WebHttpBinding(), Consts.WebHttpAddress);
foreach (var endpoint in host.Description.Endpoints)
{
if (endpoint.Address.Uri.Scheme.StartsWith("http"))
{
foreach (var operation in endpoint.Contract.Operations)
{
operation.OperationBehaviors.Add(new ClientJsonDateFormatter());
}
endpoint.Behaviors.Add(new WebHttpBehavior());
}
}
ClientJsonDateFormatter is simple class which just applies formatter ClientJsonDateFormatter
public class ClientJsonDateFormatter : IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { }
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.Formatter = new ResponseJsonFormatter(operationDescription);
}
public void Validate(OperationDescription operationDescription) { }
}
In the formatter we took imput and serialize it with the changed Serializer:
public class ResponseJsonFormatter : IDispatchMessageFormatter
{
OperationDescription Operation;
public ResponseJsonFormatter(OperationDescription operation)
{
this.Operation = operation;
}
public void DeserializeRequest(Message message, object[] parameters)
{
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
string json=Newtonsoft.Json.JsonConvert.SerializeObject(result);
byte[] bytes = Encoding.UTF8.GetBytes(json);
Message replyMessage = Message.CreateMessage(messageVersion, Operation.Messages[1].Action, new RawDataWriter(bytes));
replyMessage.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
return replyMessage;
}
}
And to send information to client we need data writer - RawDataWriter. Its implementation is simple:
class RawDataWriter : BodyWriter
{
byte[] data;
public RawDataWriter(byte[] data)
: base(true)
{
this.data = data;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("Binary");
writer.WriteBase64(data, 0, data.Length);
writer.WriteEndElement();
}
}
Applying all code will result in returning date in more friendly format:
"DateTime":"2018-08-28T20:56:48.6411976+02:00"
To show it in practice I created example in the github branch DateTimeFormatter.
Please check also this answer as very likely you also will need it.
There is a limitation in JSON to convert DateTime, specially according to your case.
Please see http://msdn.microsoft.com/en-us/library/bb412170(v=vs.110).aspx
and read the section Dates/Times and JSON
To resolve this problem, I simply changed the type of serialization from JSON to XML for all the calls including DateTime.
After long time discussion ,I have find out the solution for it.
Please Use the following Code to Solve serialized date..
[IgnoreDataMember]
public DateTime? PerformanceDate { get; set; }
[DataMember(EmitDefaultValue = false, Name = "PerformanceDate")]
public string UpdateStartDateStr
{
get
{
if (this.PerformanceDate.HasValue)
return this.PerformanceDate.Value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture);
else
return null;
}
set
{
// should implement this...
}
}
In CDI, how do I configure my beans?
Let's say I have this code:
class JawaBotApp {
private void init( String configFilePathString ) throws JawaBotException {
ConfigBean cb = new JaxbConfigPersister(configFilePathString).load();
JawaBotApp.jawaBot = JawaBot.create( cb );
}
}
class JawaBot {
public static JawaBot create( ConfigBean cb ) throws JawaBotException{
JawaBot bot = new JawaBot();
bot.applyConfig(cb);
bot.init();
return bot;
}
}
How would I convert it so both could be CDI beans?
I thought about annotating the create() with #Produces, however that would need to have it non-static, and rewrite it so the ConfigBean gets injected, which would need to rewrite JaxbConfigPersister or create a wrapper object... Too much work for nothing.
Is there better approach?
Something like:
class JawaBot {
#Inject public JavaBot(#JawaConfig String configFilePathString) {
...
}
}
Then you just need to produce an #JawaConfig String somewhere which represents your configuration. This could then be mocked out with something like an alternative or specialize to give you a diff config, or just some silly little #Producer that looks at some other external file/setting.
Then you just #Inject a JawaBot when you want it instead of all the other setup, and everything just lives in the injected constructor.