swashbuckle openapi 3 write example and description for the dynamically generated model classes - openapi

My model properties definition is coming from a json file so using reflection to write the classes to be shown under schema on resulting swagger page.
foreach (var model in Models)
{
if (!ModelTypes.ContainsKey(model.Key))
{
anyNonCompiledModel = true;
BuildModelCodeClass(modelComponentBuilder, model.Value);//Build model classes
}
}
BuildModelCodeEnd(modelComponentBuilder);
if (anyNonCompiledModel)
{
CSharpCompiler compiler = new CSharpCompiler();
compiler.AddReference(typeof(object));
compiler.AddReference(typeof(ResourceFactory));
compiler.AddReference(typeof(System.Runtime.Serialization.DataContractResolver));
compiler.AddReference(typeof(System.Runtime.Serialization.DataContractAttribute));
var types = compiler.Compiler(modelComponentBuilder.ToString()); //write model classes
foreach (var type in types)
{
ModelTypes.Add(type.Name, type);
}
}
public void BuildModelCodeClass(StringBuilder modelComponentBuilder, MetadataModelEntity model)
{
modelComponentBuilder.AppendLine($"public class {model.Name} {{");
foreach (var p in model.Data.Properties)
{
if (p.Obsoleted) continue;
if (p.Type.Type == "array")
{
modelComponentBuilder.AppendLine($" public {p.Type.ArrayType.ObjectName}[] {p.Name} {{get;set;}}");
}
else
{
//primitive types
modelComponentBuilder.AppendLine($" public {p.Type.ObjectName} {p.Name} {{get;set;}}");
}
}
modelComponentBuilder.AppendLine(
#"}
");
}
If i provide the description and example like following (in BuildModelCodeClass, inside the loop) then the example and description displays for me.
if (!string.IsNullOrWhiteSpace((string)p.Example))
{
modelComponentBuilder.AppendLine($" ///<example>{p.Example}</example>");
}
if (!string.IsNullOrWhiteSpace((string)p.Description))
{
modelComponentBuilder.AppendLine($" ///<description>{p.Description}</description>");
}
However, i dont want to do above.
I want to write my models via the open api and not via the C# Compiler, is it possible?
I want to show example and description via schema (may be under paths some where). How can i do this? Context has my models info available that i can interact with here.
public class SwaggerDocumentFilter : IDocumentFilter
{
SwaggerDocument _swaggerDocument;
public SwaggerDocumentFilter(object apiConfigure)
{
_swaggerDocument = ((ApiGatewayConfiguration)apiConfigure).SwaggerDocument;
}
public void Apply(OpenApiDocument document, DocumentFilterContext context)
{
if (document.Info.Extensions == null || !document.Info.Extensions.ContainsKey(SwaggerEndpoint.ExtensionDocName)) return;
var openIdString = document.Info.Extensions[SwaggerEndpoint.ExtensionDocName] as OpenApiString;
if (openIdString == null) return;
var docName = openIdString.Value;
SwaggerEndpoint endpoint = _swaggerDocument.SwaggerEndpoints.SingleOrDefault(x => x.Name == docName);
if (endpoint == null) return;
//Add server objects
document.Servers = endpoint.ServerObjects;
//Add Tags objects
document.Tags = endpoint.Tags;
//Set swagger paths objects
var pathsObjects = _swaggerDocument.GetPathsObject(docName, context);
if (pathsObjects.IsValid())
{
pathsObjects.ToList().ForEach(
item => document.Paths.Add(item.Key, item.Value)
);
}
//Add Schema components
//Add Example/Examples
}
}

Following helped
https://github.com/domaindrivendev/Swashbuckle.WebApi/issues/162
AddSchemaExamples.cs
public class AddSchemaExamples : ISchemaFilter
{
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
if (type == typeof(Product))
{
schema.example = new Product
{
Id = 123,
Type = ProductType.Book,
Description = "Treasure Island",
UnitPrice = 10.0M
};
}
}
}
SwaggerConfig.cs
httpConfig
.EnableSwagger(c =>
{
c.SchemaFilter<AddSchemaExamples>()
});
My implementation for the Apply since model is dynamic
if (model != null)
{
schema.Description = model.Description;
foreach (var p in schema.Properties)
{
var mp = model.Data.Properties.SingleOrDefault(x => x.Name == p.Key);
if (mp != null)
{
if (!string.IsNullOrWhiteSpace(mp.Description))
{
p.Value.Description = mp.Description;
}
if(!string.IsNullOrWhiteSpace(mp.Example))
{
p.Value.Example =
new Microsoft.OpenApi.Any.OpenApiString(mp.Example.ToString());
}
}
}
}

Related

how can I write generic queries in entity framework?

I have 3 methods these are same methods only some parameters will be change I want to write one method how can i write
public string method1(int id)
{
var getAllStudents = rep.Students.Where(e => e.StudentId == id).ToList();
foreach (var item in getAllStudents)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
public string method2(int id)
{
var getAllTeachers = rep.Teachers.Where(e => e.TeacherId == id).ToList();
foreach (var item in getAllTeachers)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
public string method3(int id)
{
var getAllClasses = rep.Classes.Where(e => e.ClassId == id).ToList();
foreach (var item in getAllClasses)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
I think there is very easy way to write 1 method. the think is where parameter has different id..
Thanks.
Avoid conditional logic based on arguments. This leads to fragile code because every parameter combination has to be tested to be considered reliable. This leads to complex code that is easily prone to bugs. Having simpler single-purpose methods are typically much more reliable and easier to understand and maintain.
For instance given your example and assuming that "rep" was your instance's DbContext...
public bool IsActiveStudent(int id)
{
bool result = rep.Students.Any(x => x.StudentId == id && x.IsActive);
return result;
}
public bool IsActiveTeacher(int id)
{
bool result = rep.Teachers.Any(x => x.TeacherId == id && x.IsActive);
return result;
}
public bool IsActiveClass(int id)
{
bool result = rep.Classes.Any(x => x.ClassId == id && x.IsActive);
return result;
}
These can be essentially one-liners by simply returning the .Any() result. I tend to favour selecting the result into a variable first and returning it on a separate line since it makes it easier to breakpoint and inspect.
If you need to return a string for "Ok" vs. "Error" then:
return result ? "OK" : "Error";
Methods should strive to do one thing, and do it well. Easy to understand and troubleshoot if need be. Adding parameters and conditional code inside the method merely makes the code more volatile and leaves openings for bugs. In the end it doesn't make the code much shorter when the initial method could be simplified.
You can not overload methods if they signatures are the same.
You have two methods with the same signature:
public string checkexist(int id)
What you can do is to rename your methods, like this:
public interface WriteSomethingHere {
public boolean isStudentExist(int id);
public boolean isTeacherExist(int id);
public boolean isClassExist(int id);
}
I just found answer using generic repo
public T GetEntity<T>(int Id)
where T : class
{
using (MyEntities rpContext = new MyEntities())
{
return rpContext.Set<T>().Find(e => e.Id == Id);
}
}
after calling
var entityStudent = GetEntity<Student>(1);
var entityTeacher = GetEntity<Teacher>(1);
var entityClasses = GetEntity<Classes>(1);
You have Create Enumeration
Public Enum ParameterStaus:short
{
Student=1,
Teacher=2,
Classess=3
}
public string method2(int id.ParameterStatus status)
{
if(status==ParameterStatus.Teacher)
{
var getAllTeachers = rep.Teachers.Where(e => e.TeacherId == id).ToList();
foreach (var item in getAllTeachers )
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
}
Else if(status==ParameterStatus.Student)
{
var getAllStudents = rep.Students.Where(e => e.StudentId == id).ToList();
foreach (var item in getAllStudents)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
Else
{
var getAllClasses = rep.Classes.Where(e => e.ClassId == id).ToList();
foreach (var item in getAllClasses)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
}

How To Find data by passing List of IMongoQuery

Below is my code where i am passing List showing no error during building solution but during run time its showing error.
An Array value cannot be written to the root level of a BSON document.
My Code Is :
public IQueryable<Folder> GetFolderByIdList(List<IMongoQuery> GraphIdList)
{
if (ApplicationDbContext.ServerIsDown) return null;
_FolderList.Clear();
if (!GraphIdList.Any())
{
return null;
}
var FolderData = db.Folder.Find(GraphIdList.ToBsonDocument()).ToList();
if (FolderData.Count() > 0)
{
foreach (Folder item in FolderData)
{
_FolderList.Add(item);
}
}
var result = _FolderList.AsQueryable();
return result;
}
and below is my code what i have pass in GraphIdList
var UserFilesData = planetDriveObj.GetFilesOfFolder(
Query.And(
Query<UserFiles>.EQ(u => u.CreatorUserID, userInfoId),
Query<UserFiles>.Matches(u => u.Title, fileTitle)));
foreach(var c in UserFilesData.ToList())
{
idList.Add(Query.And(
Query<Graph>.EQ(u => u.GraphID, c.GraphID),
Query<Graph>.EQ(u => u.isHidden, true)));
}
var GraphData = GraphRepObj.getGraphDataBYIdList(idList);

how to add extend breeze entity types with metadata pulled from property attributes

I want to get the custom attributes, mentioned below, in breeze dataService (client side).
namespace Tam.Framework.Web.Models
{
[ViewAttribute("app/views/Employee.html")]//this custom class attribute
public class Employee : BaseEntity
{
protected override string OnGetDescriptor()
{
return "some description";
}
public string FirstName { get; set; }
[Display(Name = "LAST NAME")]//this custom property attribute
public string LastName { get; set; }
}
}
On the server, add logic to the Metadata controller action to supplement the standard metadata with the display attribute properties:
[HttpGet]
public virtual string Metadata()
{
// Extend metadata with extra attributes
var metadata = JObject.Parse(this.ContextProvider.Metadata());
var ns = metadata["schema"]["namespace"].ToString();
foreach (var breezeEntityType in metadata["schema"]["entityType"])
{
var typeName = ns + "." + breezeEntityType["name"].ToString();
var entityType = BuildManager.GetType(typeName, true);
foreach (var propertyInfo in entityType.GetProperties())
{
var attributes = propertyInfo.GetAllAttributes();
var breezePropertyInfo = breezeEntityType["property"].SingleOrDefault(p => p["name"].ToString() == propertyInfo.Name);
if (breezePropertyInfo == null)
continue;
// handle display attribute...
var displayAttribute = attributes.OfType<DisplayAttribute>().FirstOrDefault();
if (displayAttribute != null)
{
var displayName = displayAttribute.GetName();
if (displayName != null)
breezePropertyInfo["displayName"] = displayName;
var displayOrder = displayAttribute.GetOrder();
if (displayOrder != null)
breezePropertyInfo["displayOrder"] = displayOrder;
var autogenerateField = displayAttribute.GetAutoGenerateField();
if (autogenerateField != null)
breezePropertyInfo["autoGenerateField"] = autogenerateField;
}
// allowEmptyStrings.
if (propertyInfo.PropertyType == typeof(string))
{
breezePropertyInfo["allowEmptyStrings"] = true;
var requiredAttribute = attributes.OfType<RequiredAttribute>().FirstOrDefault();
if (requiredAttribute != null && !requiredAttribute.AllowEmptyStrings)
breezePropertyInfo["allowEmptyStrings"] = false;
}
// todo: handle other types of attributes...
}
}
return metadata.ToString();
}
On the client, fetch the metadata and supplement the breeze entity type with the custom metadata.
function initializeMetadataStore(metadataStore, metadata) {
var metadataType, metadataProperty, entityProperty, i, j;
for (i = 0; i < metadata.schema.entityType.length; i++) {
metadataType = metadata.schema.entityType[i];
var entityType = metadataStore.getEntityType(metadataType.name);
for (j = 0; j < metadataType.property.length; j++) {
metadataProperty = metadataType.property[j];
entityProperty = entityType.getProperty(metadataProperty.name);
if (entityProperty) {
if (typeof metadataProperty.displayName !== 'undefined') {
entityProperty.displayName = metadataProperty.displayName;
}
if (typeof metadataProperty.displayOrder !== 'undefined') {
entityProperty.displayOrder = metadataProperty.displayOrder;
}
if (typeof metadataProperty.autoGenerateField !== 'undefined') {
entityProperty.autoGenerateField = metadataProperty.autoGenerateField;
}
if (typeof metadataProperty.allowEmptyStrings !== 'undefined') {
entityProperty.allowEmptyStrings = metadataProperty.allowEmptyStrings;
}
}
}
}
}
var entityManager = ....something...;
entityManager.fetchMetadata(function (metadata) {
return initializeMetadataStore(entityManager.metadataStore, metadata);
});
now the additional metadata is available in the breeze entity type...
var propertyDisplayName = myEntity.entityType.getProperty('lastName').displayName;
var manager = configureBreezeManager();
function configureBreezeManager() {
breeze.NamingConvention.camelCase.setAsDefault();
var mgr = new breeze.EntityManager('api/breeze');
model.configureMetadataStore(mgr.metadataStore);
mgr.fetchMetadata(function (metadata) {
return initializeMetadataStore(mgr.metadataStore, metadata);
});
return mgr;
};
function initializeMetadataStore(metadataStore, metadata) {
breeze.NamingConvention.defaultInstance = breeze.NamingConvention.none;
var metadataType, metadataProperty, entityProperty, i, j;
for (i = 0; i < metadata.schema.entityType.length; i++) {
metadataType = metadata.schema.entityType[i];
var entityType = metadataStore.getEntityType(metadataType.name);
for (j = 0; j < metadataType.property.length; j++) {
metadataProperty = metadataType.property[j];
entityProperty = entityType.getProperty(metadataProperty.name);
if (entityProperty) {
if (typeof metadataProperty.displayName !== 'undefined') {
entityProperty.displayName = metadataProperty.displayName;
}
if (typeof metadataProperty.displayOrder !== 'undefined') {
entityProperty.displayOrder = metadataProperty.displayOrder;
}
if (typeof metadataProperty.autoGenerateField !== 'undefined') {
entityProperty.autoGenerateField = metadataProperty.autoGenerateField;
}
if (typeof metadataProperty.allowEmptyStrings !== 'undefined') {
entityProperty.allowEmptyStrings = metadataProperty.allowEmptyStrings;
}
}
}
}
}
var readData = function (entityName, observableResults, showLog) {
if (!entityName || !observableResults)
return null;
var query = new breeze.EntityQuery()
.from(entityName);
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
}
function readEmployee() {
return breezeDataService.readData("Employees", employees, true).then(function () {
var propertyDisplayName = employees()[0].entityType.getProperty('lastName').displayName;//error displayName undefined
}
}
when I get list of entity by readData function that list (observableResults[0]) have not any displayName but I add displayName and checked it by initializeMetadataStore function is correct
FINALLY!!!!! I found it it because of breeze.NamingConvention.camelCase.setAsDefault();

Replace bookmark contents in Word using OpenXml

I can't find any working code examples for replacing bookmark contents. The code should be able to handle both the case replace empty bookmark and replace bookmark with preexisting content.
For example: If I have this text in a Word document:
"Between the following periods comes Bookmark1.. Between next periods comes Bookmark2.."
and I want to insert the text "BM1" between the first periods, and "BM2" between the next.
After the first replacement run, the replacements are inserted correctly.
But after the next replacement run, all of the text on the line after Bookmark1 gets deleted, and then the replacement for Bookmark2 gets inserted.
This is my c# code:
var doc = WordprocessingDocument.Open(#"file.docx", true);
public static Dictionary<string, wd.BookmarkStart> FindAllBookmarksInWordFile(WordprocessingDocument file)
{
var bookmarkMap = new Dictionary<String, wd.BookmarkStart>();
foreach (var headerPart in file.MainDocumentPart.HeaderParts)
{
foreach (var bookmarkStart in headerPart.RootElement.Descendants<wd.BookmarkStart>())
{
if (!bookmarkStart.Name.ToString().StartsWith("_"))
bookmarkMap[bookmarkStart.Name] = bookmarkStart;
}
}
foreach (var bookmarkStart in file.MainDocumentPart.RootElement.Descendants<wd.BookmarkStart>())
{
if (!bookmarkStart.Name.ToString().StartsWith("_"))
bookmarkMap[bookmarkStart.Name] = bookmarkStart;
}
return bookmarkMap;
}
/*extension methods*/
public static bool IsEndBookmark(this OpenXmlElement element, BookmarkStart startBookmark)
{
return IsEndBookmark(element as BookmarkEnd, startBookmark);
}
public static bool IsEndBookmark(this BookmarkEnd endBookmark, BookmarkStart startBookmark)
{
if (endBookmark == null)
return false;
return endBookmark.Id.Value == startBookmark.Id.Value;
}
/* end of extension methods */
public static void SetText(BookmarkStart bookmark, string value)
{
RemoveAllTexts(bookmark);
bookmark.Parent.InsertAfter(new Run(new Text(value)), bookmark);
}
private static void RemoveAllTexts(BookmarkStart bookmark)
{
if (bookmark.ColumnFirst != null) return;
var nextSibling = bookmark.NextSibling();
while (nextSibling != null)
{
if (nextSibling.IsEndBookmark(bookmark) || nextSibling.GetType() == typeof(BookmarkStart))
break;
foreach (var item in nextSibling.Descendants<Text>())
{
item.Remove();
}
nextSibling = nextSibling.NextSibling();
}
}
I have looked around a long time for a general solution.
Any help is appreciated! -Victor
Maybe this can help you
first:delete bookmarkContent
second:find bookMark => insert value
public static void InsertTest1(WordprocessingDocument doc, string bookMark, string txt)
{
try
{
RemoveBookMarkContent(doc, bookMark);
MainDocumentPart mainPart = doc.MainDocumentPart;
BookmarkStart bmStart = findBookMarkStart(doc, bookMark);
if (bmStart == null)
{
return;
}
Run run = new Run(new Text(txt));
bmStart.Parent.InsertAfter<Run>(run, bmStart);
}
catch (Exception c)
{
//not Exception
}
}
public static void RemoveBookMarkContent(WordprocessingDocument doc, string bmName)
{
BookmarkStart bmStart = findBookMarkStart(doc, bmName);
BookmarkEnd bmEnd = findBookMarkEnd(doc, bmStart.Id);
while (true)
{
var run = bmStart.NextSibling();
if (run == null)
{
break;
}
if (run is BookmarkEnd && (BookmarkEnd)run == bmEnd)
{
break;
}
run.Remove();
}
}
private static BookmarkStart findBookMarkStart(WordprocessingDocument doc, string bmName)
{
foreach (var footer in doc.MainDocumentPart.FooterParts)
{
foreach (var inst in footer.Footer.Descendants<BookmarkStart>())
{
if (inst.Name == bmName)
{
return inst;
}
}
}
foreach (var header in doc.MainDocumentPart.HeaderParts)
{
foreach (var inst in header.Header.Descendants<BookmarkStart>())
{
if (inst.Name == bmName)
{
return inst;
}
}
}
foreach (var inst in doc.MainDocumentPart.RootElement.Descendants<BookmarkStart>())
{
if (inst is BookmarkStart)
{
if (inst.Name == bmName)
{
return inst;
}
}
}
return null;
}
This code works but not when the bookmark is placed within a field/formtext (a gray box).
private static void SetNewContents(wd.BookmarkStart bookmarkStart, string text)
{
if (bookmarkStart.ColumnFirst != null) return;
var itemsToRemove = new List<OpenXmlElement>();
var nextSibling = bookmarkStart.NextSibling();
while (nextSibling != null)
{
if (IsEndBookmark(nextSibling, bookmarkStart))
break;
if (nextSibling is wd.Run)
itemsToRemove.Add(nextSibling);
nextSibling = nextSibling.NextSibling();
}
foreach (var item in itemsToRemove)
{
item.RemoveAllChildren();
item.Remove();
}
bookmarkStart.Parent.InsertAfter(new wd.Run(new wd.Text(text)), bookmarkStart);
}

Merge Self-tracking entities

Graph of objects stored in the database and the same object graph is serialized into a binary package. Package is transmitted over the network to the client, then it is necessary to merge data from the package and data from the database.
Source code of merge:
//objList - data from package
var objectIds = objList.Select(row => row.ObjectId).ToArray();
//result - data from Database
var result = SomeService.Instance.LoadObjects(objectIds);
foreach (var OSobj in objList)
{
var obj = result.Objects.ContainsKey(OSobj.ObjectId)
? result.Objects[OSobj.ObjectId]
: result.Objects.CreateNew(OSobj.ObjectId);
var targetObject = result.DataObjects.Where(x => x.ObjectId == OSobj.ObjectId).FirstOrDefault();
targetObject.StopTracking();
var importedProperties = ImportProperties(targetObject.Properties, OSobj.Properties);
targetObject.Properties.Clear();
foreach (var property in importedProperties)
{
targetObject.Properties.Add(property);
}
targetObject.StartTracking();
}
return result;
And code of ImportProperties method:
static List<Properties> ImportProperties(
IEnumerable<Properties> targetProperties,
IEnumerable<Properties> sourceProperties)
{
Func<Guid, bool> hasElement = targetProperties
.ToDictionary(e => e.PropertyId, e => e)
.ContainsKey;
var tempTargetProperties = new List<Properties>();
foreach (var sourceProperty in sourceProperties)
{
if (!hasElement(sourceProperty.PropertyId))
{
sourceProperty.AcceptChanges();
tempTargetProperties.Add(sourceProperty.MarkAsAdded());
}
else
{
sourceProperty.AcceptChanges();
tempTargetProperties.Add(sourceProperty.MarkAsModified());
}
}
return tempTargetProperties;
}
Server save incoming changes like this :
_context.ApplyChanges("OSEntities.Objects", entity);
_context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
When the server tries to save the changes occur exception:
AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
But if I change the code of ImportProperties method, the error does not occur and the changes are saved successfully:
static List<Properties> ImportProperties(
IEnumerable<Properties> targetProperties,
IEnumerable<Properties> sourceProperties)
{
Func<Guid, bool> hasElement = targetProperties.ToDictionary(e => e.PropertyId, e => e).ContainsKey;
var tempTargetProperties = new List<Properties>();
foreach (var sourceProperty in sourceProperties)
{
if (!hasElement(sourceProperty.PropertyId))
{
var newProp = new Properties
{
ElementId = sourceProperty.ElementId,
Name = sourceProperty.Name,
ObjectId = sourceProperty.ObjectId,
PropertyId = sourceProperty.PropertyId,
Value = sourceProperty.Value
};
tempTargetProperties.Add(newProp);
}
else
{
var modifiedProp = new Properties
{
ElementId = sourceProperty.ElementId,
Name = sourceProperty.Name,
ObjectId = sourceProperty.ObjectId,
PropertyId = sourceProperty.PropertyId,
Value = sourceProperty.Value
};
modifiedProp.MarkAsModified();
tempTargetProperties.Add(modifiedProp);
}
}
return tempTargetProperties;
}
Why is there an exception?
When you transport an object graph (Entity with n-level deep navigation properties) to a client application the entities will record any changes made in their respective change trackers. When entity (or object graph) is sent back to the server side of the application basically all you need to do is:
try
{
using(Entities context = new Entities())
{
context.ApplyChanges(someEntity);
context.SaveChanges();
}
}
catch
{
...
}
I don't see the need of all the code above you posted. What are you trying to achieve with that code?