Suppose I have a business object: (C#)
public class ModelA {
public int id {get;set;}
[Required, MyCustomAttribute(...)]
public string str {get;set;}
}
Then I have a ModelAController: (C#)
[Route("api/[controller]")]
[ApiController]
public class ModelAController : Controller
{
// ... some contructors and readonly database ...
[HttpPut("read")]
public ActionResult<ModelA> Read() {
return db.Read<ModelA>();
}
}
Then I have some Vue component: (vue.js)
import ...
export default {
data () {
return {
annotations: '',
model: '',
};
},
created: function()
{
this.values = Read('ModelA'); // reads data in json format returned by ModelAController.Read()
this.annotation = // ?????
},
};
My question is; From a Vue component, how do I access the annotations "Required" and "MyCustomAttribute" and others. Should I add a method in my controller to get these Attribute?
[HttpPut("attributes")]
public ActionResult<Attribute[]> Attributes(string propertyName) {
return getAttributesOf(propertyName);
// getAttributesOf("str") would return Attribute[]{ RequiredAttribute, MyCustomAttribute(...)}
}
Is there a better way?
Related
I am using springfox version 2.9.2 and swagger annotations 1.5.x. The ApiModel annotations support the discriminator, subTypes and parent attribute which are required to make polymorphism work but I am not seeing the correct apidocs generated to enable polymorphism.
Here is my annotated code.
#RestController
#RequestMapping("/api/vehicles")
public class VehicleController {
private static final Logger LOGGER = LoggerFactory.getLogger(VehicleController.class);
#PostMapping(consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE})
void post(#RequestBody Vehicle anyVehicle) {
LOGGER.info("Vehicle : {}", anyVehicle);
}
}
#ApiModel(discriminator = "type", subTypes = {Car.class, Bike.class})
public class Vehicle {
String brand;
String type;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
#ApiModel(parent = Vehicle.class)
public class Car extends Vehicle {
int noOfDoors;
boolean powerWindows;
public int getNoOfDoors() {
return noOfDoors;
}
public void setNoOfDoors(int noOfDoors) {
this.noOfDoors = noOfDoors;
}
public boolean isPowerWindows() {
return powerWindows;
}
public void setPowerWindows(boolean powerWindows) {
this.powerWindows = powerWindows;
}
}
#ApiModel(parent = Vehicle.class)
public class Bike extends Vehicle {
boolean pillion;
public boolean isPillion() {
return pillion;
}
public void setPillion(boolean pillion) {
this.pillion = pillion;
}
}
When the docs get generated is basically shows one endpoint which handles a POST request and takes in a Vehicle as the model.
Is what I am doing here supposed to work? Can someone point me to a working example of this with SpringFox that I can look at?
Support for discriminator is not available in Swagger UI yet. You can follow these issues for status updates:
Discriminator does not switch schema
subTypes not displayed in model
Is there any way to add a custom data annotation for metadata? I find than [DefaultValue] doesn't work
namespace PROJECT.Common.Attributes
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class MyDefaultValueAttribute : Attribute, IMetadataAware
{
public string DefaultValue;
private dynamic _DefaultValue;
public MyDefaultValueAttribute(string m_value_tx)
{
_DefaultValue = m_value_tx;
}
public MyDefaultValueAttribute(bool m_default_yn)
{
_DefaultValue = m_default_yn;
}
public MyDefaultValueAttribute(Int32 m_default_no)
{
_DefaultValue = m_default_no;
}
public MyDefaultValueAttribute(DateTime m_default_dt)
{
_DefaultValue = m_default_dt;
}
public MyDefaultValueAttribute(decimal m_defaul_tx)
{
_DefaultValue = m_defaul_tx;
}
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["DefaultValue"] = _DefaultValue;
}
}
and on i created a model binder but the problem is, the data annotation that i make only works for string..
i am passing dynamic on my constructor...
any help is appreciated... I clearly want custom annotations
THANKS
**Hi Friends,
I am try to create custom widget in Orchard to display Student detail it show in widget list in admin panel but throw error when click on save button when i try to use it.it shows error
error is:-
And my code is
Model Code is:-
public class studentPart :ContentPart<studentPartRecord>
{
public string Rollno { get { return Record.Rollno; } set { Record.Rollno =value; } }
public string Name { get { return Record.Name; } set { Record.Name = value; } }
public string Class { get { return Record.Class; } set { Record.Class = value; } }
}
public class studentPartRecord :ContentPartRecord
{
public virtual string Rollno { get; set; }
public virtual string Name { get; set; }
public virtual string Class { get; set; }
}
Migration code is:-
public int Create() {
// Creating table tb_Student_studentPartRecord
SchemaBuilder.CreateTable("tb_Student_studentPartRecord", table =>table
.ContentPartRecord()
.Column("Rollno", DbType.String)
.Column("Name", DbType.String)
.Column("Class", DbType.String)
);
return 1;
}
public int UpdateFrom1()
{
// Creating table tb_EmpData_EmpDataPartRecord
ContentDefinitionManager.AlterPartDefinition(typeof(studentPart).Name,
builder => builder.Attachable());
ContentDefinitionManager.AlterTypeDefinition("StudentWidget",
cfg => cfg
.WithPart("studentPart")
.WithPart("WidgetPart")
.WithPart("CommonPart")
.WithPart("IdentityPart")
.WithSetting("Stereotype", "Widget"));
return 2;
}
Driver code is:-
public class studentPartDriver :ContentPartDriver<studentPart>
{
protected override DriverResult Display(studentPart part, string displayType, dynamic shapeHelper)
{
return ContentShape("Parts_student",
() => shapeHelper.Parts_student(Rollno:part.Rollno,Name:part.Name,Class:part.Class));
}
//GET
protected override DriverResult Editor(studentPart part, dynamic shapeHelper)
{
return ContentShape("Parts_student_Edit",
() => shapeHelper.EditorTemplate(TemplateName: "Parts/student", Model: part, Prefix: Prefix));
}
//POST
protected override DriverResult Editor(studentPart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
Handler Code is:-
public class studentPartHandler :ContentHandler
{
public studentPartHandler(IRepository<studentPartRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
Filters.Add(new ActivatingFilter<studentPart>("student"));
}
}
Please help me . Thanks in Advance
Change studentPart to StudentPart
Change studentPartRecord to StudentPartRecord
Change SchemaBuilder.CreateTable("tb_Student_studentPartRecord" to SchemaBuilder.CreateTable("StudentPartRecord"
As Bertrand says, your class names should be pascal case to comply with C# conventions, and the table name you pass to CreateTable should be the same as the record's class name. Orchard takes care of prefixing the final database table for you.
I'm trying to pass data from JQuery to an MVC 4 controller. The controller gets invoked, but no data is passed. In the past I always just used form serialization, but that's not appropriate here.
My Controller:
[HttpPost]
public ActionResult Write(VideoSessionEnvelope envelope)
{
if (ModelState.IsValid)
{
envelope = Log.Write(envelope);
}
var result = Json(envelope);
return result;
}
We use an envelope class as a container for all view models
public class VideoSessionEnvelope : BaseEnvelope
{
public VideoSessionEnvelope()
{
SessionStart = new VideoSessionStartViewModel();
}
public Guid? LogEntryID { get; set; }
public VideoSessionStartViewModel SessionStart { get; set; }
}
}
The view model
public class VideoSessionStartViewModel: IViewModel
{
public string SessionId { get; set; }
public int UserId { get; set; }
public string Message { get; set; }
}
And finally the javascript
var Logging = Logging || {};
Logging.VideoSession = function () {
var Start = function (sessionId, userId, message) {
var envelope = {
SessionStart: {
"SessionId": sessionId,
"UserId": userId,
"Message": message
}
}
var data = JSON.stringify(envelope);
$.ajax({
type: "POST",
url: "/Logging/Write",
data: data,
datatype: "application/json",
success: function (result) {
return result;
},
error: function (request, status, error) {
return error;
}
});
};
return {
Start: Start
};
}();
According to Firebug the data is passed as
JSON
SessionStart Object { SessionId="sessionIdVal", UserId=123, Message="messageValue"}
Message "messageValue"
SessionId "sessionIdVal"
UserId 123
The controller gets called, but the properties in the view model are always null. I've tried several variations on the theme, nothing seems to work.
Try wrapping your data in a literal with the name as envelope so it will be picked up by the Model Binder:
data: { envelope: data },
UPDATE
Remove the call to JSON.stringify(), it is not strictly necessary to serialize the object literal.
I've been trying to implement David Hayden's Orchard CMS and ASP .NET Web API http://www.davidhayden.me/blog/orchard-cms-and-asp.net-web-api, but I'm running into problems, basically getting a page not found.
This is what I have:
Under my controllers
ContactViewModel.cs
namespace Sunkist.ContactManager.Controllers
{
public class ContactsController : ApiController
{
private readonly IContentManager _contentManager;
public ContactsController(IContentManager contentManager)
{
_contentManager = contentManager;
}
public IEnumerable<ContactViewModel> Get()
{
return _contentManager
.Query(VersionOptions.Published, "Contact")
.List()
.Select(c => new ContactViewModel(c));
}
public ContactViewModel Get(int id)
{
var contact = _contentManager.Get(id);
if (contact == null)
throw new HttpResponseException
(new HttpResponseMessage(HttpStatusCode.NotFound));
return new ContactViewModel(contact);
}
}
}
ViewModel folder
ViewModel.cs
namespace Sunkist.ContactManager.ViewModel
{
public class ContactViewModel
{
private Orchard.ContentManagement.ContentItem c;
public ContactViewModel(Orchard.ContentManagement.ContentItem c)
{
// TODO: Complete member initialization
this.c = c;
}
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
}
}
and migration
namespace Sunkist.ContactManager {
public class Migrations : DataMigrationImpl {
public int Create() {
// Creating table ContactRecord
SchemaBuilder.CreateTable("ContactRecord", table => table
.ContentPartRecord()
.Column("Name", DbType.String)
.Column("Address", DbType.String)
.Column("City", DbType.String)
);
return 1;
}
}
}
I'm new to both Orchard and .Net MVC, So I'm not sure what I'm doing wrong?
Double check the name of the module that contains the Web API controller.
Via VS GUI, I created a new web api controller class "TestController.cs" and could not find the correct endpoint url.
That is, until I looked at the Module.txt in the project I added the controller to. The project is "Orchard.Users", but the name in the Module.txt file is just "Users".
I was able to hit the endpoint at "http://example.com/api/users/test".
Noteworthy: I setup a route for this at ".../UsersApi", but the 'auto-magic' URL pattern still works. Code below. Also, I later added a new module to contain my api controller and it would not work until I enabled the module in the dashboard.
TestController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace Orchard.Users.Controllers
{
public class TestController : ApiController
{
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
// POST api/<controller>
public void Post([FromBody]string value)
{
}
// PUT api/<controller>/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
}
HttpRoutes.cs
using System.Collections.Generic;
using Orchard.Mvc.Routes;
using Orchard.WebApi.Routes;
public class HttpRoutes : IHttpRouteProvider
{
public void GetRoutes(ICollection<RouteDescriptor> routes)
{
foreach (RouteDescriptor routeDescriptor in GetRoutes())
{
routes.Add(routeDescriptor);
}
}
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[] {
new HttpRouteDescriptor {
Name = "UsersApi",
Priority = -10,
RouteTemplate = "usersapi/{id}",
Defaults = new {
area = "Orchard.Users",
controller = "Test",
id = RouteParameter.Optional
},
}
};
}
}