I have created Spring Boot app, in this app I have
#RestController
public class OfferController {
#RequestMapping(value = "/saveOffer", method = RequestMethod.POST)
public void saveOffer(#RequestBody Offer offer) {
//...
}
}
Offer class contain nested property of Address type
public class Offer {
private String title;
private Address address;
//... getters setters etc
}
When I'm sending JSON from UI
{
"offer": {
"title":"TheBestOffer",
"address": {
"city": "Warsaw"
}
}
}
My REST controller receives Offer, Address property is null but title property contains value "TheBestOffer" (as it was sended).
As I assume JACKSON delivered with Spring boot require some extra configuration for nested objects? I have tried to do this but it didn't work :/
Spring does this automatically, i think your problem is with the json.
You need to remove offer tag.
{
"title":"TheBestOffer",
"address": {
"city": "Warsaw"
}
}
Related
First of all, excuse my English, it's very bad. I am using MassTransit with Azure Service Bus for asynchronous communication between microservices. By their own definition, and to avoid generating dependencies between them, messages sent between different microservices are defined in each of them, that is, they are part of different namespaces. The automatic management of MassTransit causes queues and topics to be managed by the object type, which prevents the microservices that consume a message from receiving the messages sent by the microservice publisher. The same thing happens with two classes with the same properties in the same namespace but with a different class name.
Is there any way to solve this?
The options that have occurred to me are:
Remove the namespace from the endpoint of the destination address, naming it only with the name of the class.
That MassTransit can manage the creation of queues and topics based on the serialization of the object, instead of managing it based on the object type (perhaps through some type of wrapping object?)
I leave an example that I hope can help you in understanding the problem.
//FIRST PROGRAM - MESSAGE CONSUMER
namespace Consumer
{
public class Example
{
public string PropOne { get; set; }
public string PropTwo { get; set; }
}
public class ExampleConsumer :
IConsumer<Example>
{
public List<Example> ConsumedTestObjectList { get; } = new List<Example>();
//THIS METHOD NEVER CALL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public Task Consume(ConsumeContext<ExampleConsumer> context)
{
ConsumedTestObjectList.Add(context.Message);
return Task.CompletedTask;
}
}
public class ConsumerProgram
{
public static void Main()
{
var bus = Bus.Factory.CreateUsingAzureServiceBus(sbc =>
{
var host = sbc.Host("connectionString", h => {});
});
sbc.ReceiveEndpoint(host, e =>
{
e.Consumer<ConsumerProgram.Example>(context =>
{
return Console.Out.WriteLineAsync($"Message Received: {JsonConvert.SerializeObject(context.Message)}");
});
});
bus.Start(); // This is important!
Console.WriteLine("Press any key to exit");
Console.ReadKey();
bus.Stop();
}
}
}
//SECOND PROGRAM - MESSAGE PUBLISHER
namespace Publisher
{
public class Example
{
public string PropOne { get; set; }
public string PropTwo { get; set; }
}
public class PublisherProgram
{
public static void Main()
{
var bus = Bus.Factory.CreateUsingAzureServiceBus(sbc =>
{
var host = sbc.Host("connectionString", h => {});
});
bus.Start(); // This is important!
//send new instance of Publisher.Example
var example = new Example() { PropOne = "1", PropTwo = "2" };
bus.Publish(example);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
bus.Stop();
}
}
}
Thank you very much.
regards
Borja
The message type, and the resulting name, are a key concept within MassTransit. If you want to avoid sharing assemblies between projects, that is fine, but you will need to match the entire interface (or class, in your case) name, including namespace, or it will not route properly.
Yes, you can override the entity name formatter to change how topics are named but it won't change the message type requirement for deserialization of the message (which happens, by type).
So the recommendation here is to use the same namespace for the contracts, even if they're in separate projects.
I have this ASP.NET Core 2.0 MVC Controller:
[Route("api/[controller]")]
public class SampleDataController : Controller
{
[HttpGet("[action]")]
public Example Demo()
{
return new Example("test");
}
public class Example
{
public Example(string name)
{
Name = name;
}
public string Name { get; }
public IEnumerable<Example> Demos
{
get { yield return this; }
}
}
}
When querying /api/SampleData/Demo, I get as response body:
{"name":"test","demos":[
...which is obviously very broken JSON-like output.
How and where do I have to configure my ASP.Net Core 2.0 MVC-based app to make the framework serialize circular references in a way that does not break the output? (For example, by introducing $ref and $id.)
In order to switch on references for JSON.Net serialization, you should set PreserveReferencesHandling property of SerializerSettings to PreserveReferencesHandling.Objects enum value.
In ASP.Net Core you could do it by following adjustment in Startup.ConfigureServices method:
services.AddMvc()
.AddJsonOptions(opt =>
{
opt.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
});
Now the model will be serialized to following correct JSON:
{
"$id": "2",
"name": "test",
"demos": [ { "$ref": "2" } ]
}
I'm using JsonPatchDocument with ASP.NET 4.5 and Web Api. My controller looks like this:
[HttpPatch]
[Route("MyRoute/{PersonItem1}/{PersonItem2}/")]
public IHttpActionResult ChangePerson([FromHeader]Headers, [FromBody]JsonPatchDocument<PersonDto> person)
{
// Do some stuff with "person"
}
And PersonDto:
public class PersonDto
{
public string Name { get; set; }
public string Email { get; set; }
}
Now, I may send a PATCH request that is something like:
{
"op": "op": "replace", "path": "/email", "value": "new.email#example.org"
}
Now let's say I add some data annotations:
public class PersonDto
{
public string Name { get; set; }
[MaxLength(30)]
public string Email { get; set; }
}
What is the best way to ensure this validation is honored without writing additional validation. Is it even possible?
There is the simple method:
Get your object from your repository.
Deep copy the object so you have object A and B.
Apply the change with person.ApplyUpdatesTo(objB).
Create an extension method to validate the difference between object A and B.
If the validation is good proceede, if not throw an error.
This would catch if the client was attempting to modify immutable fields or if the new information in object B violates your constraints.
Note that this is not a great solution in that you would have to change your code in two places if you happen to change your constraints.
I can DI app setting in the controller like this
private IOptions<AppSettings> appSettings;
public CompanyInfoController(IOptions<AppSettings> appSettings)
{
this.appSettings = appSettings;
}
But how to DI that in my custom class like this
private IOptions<AppSettings> appSettings;
public PermissionFactory(IOptions<AppSettings> appSetting)
{
this.appSettings = appSettings;
}
my register in Startup.cs is
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
The "proper" way
Register your custom class in the DI, the same way you register other dependencies in ConfigureServices method, for example:
services.AddTransient<PermissionFactory>();
(Instead of AddTransient, you can use AddScoped, or any other lifetime that you need)
Then add this dependency to the constructor of your controller:
public CompanyInfoController(IOptions<AppSettings> appSettings, PermissionFactory permFact)
Now, DI knows about PermissionFactory, can instantiate it and will inject it into your controller.
If you want to use PermissionFactory in Configure method, just add it to it's parameter list:
Configure(IApplicationBuilder app, PermissionFactory prov)
Aspnet will do it's magic and inject the class there.
The "nasty" way
If you want to instantiate PermissionFactory somewhere deep in your code, you can also do it in a little nasty way - store reference to IServiceProvider in Startup class:
internal static IServiceProvider ServiceProvider { get;set; }
Configure(IApplicationBuilder app, IServiceProvider prov) {
ServiceProvider = prov;
...
}
Now you can access it like this:
var factory = Startup.ServiceProvider.GetService<PermissionFactory>();
Again, DI will take care of injecting IOptions<AppSettings> into PermissionFactory.
Asp.Net 5 Docs in Dependency Injection
I recommend not passing AppSettings. A class shouldn't depend on something vague - it should depend on exactly what it needs, or close to it. ASP.NET Core makes it easier to move away from the old pattern of depending on AppSettings. If your class depends on AppSettings then you can't really see from the constructor what it depends on. It could depend on any key. If it depends on a more specific interface then its dependency is clearer, more explicit, and you can mock that interface when unit testing.
You can create an interface with the specific settings that your class needs (or something less specific but not too broad) and a class that implements it - for example,
public interface IFooSettings
{
string Name { get; }
IEnumerable Foos { get; }
}
public interface IFoo
{
string Color { get; }
double BarUnits { get; }
}
public class FooSettings : IFooSettings
{
public string Name { get; set; }
public List<Foo> FooList { get; set; }
public IEnumerable Foos
{
get
{
if (FooList == null) FooList = new List<Foo>();
return FooList.Cast<IFoo>();
}
}
}
public class Foo : IFoo
{
public string Color { get; set; }
public double BarUnits { get; set; }
}
Then add a .json file, fooSettings.json:
{
"FooSettings": {
"Name": "MyFooSettings",
"FooList": [
{
"Color": "Red",
"BarUnits": "1.5"
}, {
"Color": "Blue",
"BarUnits": "3.14159'"
}, {
"Color": "Green",
"BarUnits": "-0.99999"
}
]
}
}
Then, in Startup() (in Startup.cs) where we specify what goes into our Configuration, add fooSettings.json:
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddJsonFile($"config.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("fooSettings.json");
Finally, in ConfigureServices() (also in Startup.cs) tell it to load an instance of FooSettings, cast it as IFooSettings (so the properties appear read-only) and supply that single instance for all dependencies on IFooSettings:
var fooSettings = (IFooSettings)ConfigurationBinder.Bind<FooSettings>(
Configuration.GetConfigurationSection("FooSettings"));
services.AddInstance(typeof (IFooSettings), fooSettings);
Now your class - controller, filter, or anything else created by the DI container - can have a dependency on IFooSettings and it will be supplied from the .json file. But you can mock IFooSettings for unit testing.
Original blog post - it's mine so I'm not plagiarizing.
You can do dependency injection in your non-controller classes as well.
In your startup class,
public class Startup
{
public IConfigurationRoot Configuration { get; set; }
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
// register other dependencies also here
services.AddInstance<IConfiguration>(Configuration);
}
}
Now in your custom class, Have the constructor accept an implementation of IConfiguration
private IConfiguration configuration;
public PermissionFactory(IConfiguration configuration)
{
this.configuration = configuration;
}
public void SomeMethod()
{
var someSection = this.configuration.GetSection("SomeSection");
var someValue= this.configuration.Get<string>("YourItem:SubItem");
}
If you want to DI to action filter reference to Action filters, service filters and type filters in ASP.NET 5 and MVC 6 service filter part.
I'm working on building a WebAPI based OData service and I’m having issues with navigation links. Basically I have two classes where one has a reference to another. When I request either atom or verbose JSON I can see that I have a link between the two. However, I’d like to customize the uri to have it point to a different location rather than the default assumed by the OData library.
Using a simple example, assume that I have two entity sets called ‘entity1’ and ‘entity2’. These are exposed as OData services located at: /api/entities1 and /api/entities2 respectively.
Here’s my sample model code:
public class Entity1 {
public int ID { get; set; }
public string Name { get; set; }
public virtual Entity2 OtherEntity { get; set; }
}
public class Entity2 {
public int ID { get; set; }
public string Value { get; set; }
}
I’m using the ODataConventionModelBuilder to register these as follows:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Entity1>("entities1");
builder.EntitySet<Entity2>("entities2");
IEdmModel model = builder.GetEdmModel();
config.Routes.MapODataRoute(routeName: "OData", routePrefix: "api", model: model);
I've implemented the controller as an EntitySetController. All of this works as expected and I get the following response when I request verbose JSON:
{
"d": {
"results": [{
"__metadata": {
"id": "http://localhost:37826/api/entities1(1)",
"uri": "http://localhost:37826/api/entities1(1)",
"type": "ODataSample.Models.Entity1"
},
"OtherEntity": {
"__deferred": {
"uri": "http://localhost:37826/api/entities1(1)/OtherEntity"
}
},
"ID": 1,
"Name": "First Entity"
}]
}
}
What I’d like to do is to have the ‘OtherEntity’ field in an Entity1 instance refer to the associated Entity2 instance under /api/entities2 so that the link appears something like /api/entities2(2) (assuming the ID of the Entity2 instance is '2').
I know that I could just make the type of ‘OtherEntity’ a Uri and insert the appropriate value in my controller but that seems a bit of a hack (but I could be wrong). From what understand about OData, I believe the right way to do this is to modify the navigation property but I’m not sure how or where.
Any help is appreciated. Thanks in advance.
Cheers,
Steve
You could do something like the following:
var entities1 = builder.EntitySet<Entity1>("Entities1");
entities1.HasNavigationPropertyLink(entities1.EntityType.NavigationProperties.First(np => np.Name == "OtherEntity"),
(context, navigation) =>
{
return new Uri(context.Url.ODataLink(new EntitySetPathSegment("Entities2"), new KeyValuePathSegment(context.EntityInstance.OtherEntity.Id.ToString())));
}, followsConventions: false);