Swashbuckle.AspNetCore 5.0.0-rc4 UploadFileFilter doesn't work - asp.net-core

I need to add upload file for Swashbuckle.AspNetCore 5.0.0-rc4. In earlier version it works like:
public class SwaggerUploadFileParametersFilter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
if (operation.parameters != null)
{
var attribute =
apiDescription.ActionDescriptor.GetCustomAttributes<UploadFileParametersAttribute>()
.FirstOrDefault();
if (attribute != null)
{
operation.consumes.Add("multipart/form-data");
operation.parameters.Add(new Parameter
{
name = "file",
required = true,
type = "file",
#in = "formData"
}
);
}
}
}
}
[UploadFileParameters]
public async Task<IHttpActionResult> MyMethod([FromUri]MyMethodParams parameters)
I try to implement it using Microsoft.OpenApi.Models objects:
public class SwaggerUploadFileParametersFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var actionAttributes = context.MethodInfo.GetCustomAttributes<UploadFileParametersAttribute>().FirstOrDefault();
if (actionAttributes != null)
{
operation.RequestBody = new OpenApiRequestBody()
{
Content =
{
["multipart/form-data"] = new OpenApiMediaType()
{
Schema = new OpenApiSchema()
{
Properties =
{
["file"] = new OpenApiSchema()
{
Description = "Select file",
Type = "file"
}
}
}
}
}
};
}
}
}
But it doesn't work. I don't see file component in swagger

I took your code and some documentation from Swagger File Upload
I modified your code and added small fix
public class SwaggerUploadFileParametersFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var parameters = operation.Parameters;
if (parameters == null || parameters.Count == 0)
{
return;
}
var isUploadFile = context.ApiDescription.ActionDescriptor.Parameters.Any(x => x.ParameterType == typeof(IFormFile));
if (isUploadFile)
{
operation.RequestBody = new OpenApiRequestBody()
{
Content =
{
["multipart/form-data"] = new OpenApiMediaType()
{
Schema = new OpenApiSchema()
{
Type = "object",
Properties =
{
["file"] = new OpenApiSchema()
{
Description = "Select file", Type = "string", Format = "binary"
}
}
}
}
}
};
}
}
}
And controller:
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<IActionResult> UploadFileAsync([FromForm] IFormFile file)

Related

.net core 2.2 webapi and handling multypart request

I have .net core 2.2 webapi as backend.
My backend have to handling the requests (photo and text) from mobile application as multypart-form request.
Plz hint me how it to prpvide on backend?
this problem has solved
public class SwaggerFileOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
if (operation.OperationId == "MailWithPhotos")
{
operation.Parameters = new List<IParameter>
{
new NonBodyParameter
{
Name = "awr_file",
Required = false,
Type = "file",
In = "formData"
},
new NonBodyParameter
{
Name = "awr_message",
Required = true,
Type = "string",
In = "formData"
},
new NonBodyParameter
{
Type = "string",
In = "header",
Name = "Authorization",
Description = "token",
Required = true
}
};
}
}
}
[HttpPost]
[ProducesResponseType(typeof(ResponseMail), 200)]
public async Task<PipeResponse> MailWithPhotos([FromForm] MailwithPhoto fIleUploadAPI)
{
var file = fIleUploadAPI.awr_file; // OK!!!
var message = fIleUploadAPI.awr_message; // OK!!!
var tokenA = Request.Headers["Authorization"]; // OK!!!
var fileContentStream11 = new MemoryStream();
await fIleUploadAPI.awr_file.CopyToAsync(fileContentStream11);
await System.IO.File.WriteAllBytesAsync(Path.Combine(folderPath,
fIleUploadAPI.awr_file.FileName),
fileContentStream11.ToArray());
}
public class MailwithPhoto
{
public string awr_message { get; set; }
public string Authorization { get; set; }
public IFormFile awr_file { get; set; }
}

AuthorizeCheckOperationFilter in Swagger 5 in ASP.NET Core

I've been using this method in an older version of Swagger:
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var authAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
.Union(context.MethodInfo.GetCustomAttributes(true))
.OfType<AuthorizeAttribute>();
if (authAttributes.Any())
{
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
operation.Security = new List<IDictionary<string, IEnumerable<string>>>
{
new Dictionary<string, IEnumerable<string>>
{
{ "oauth2", new[] { "myscope" } }
}
};
}
}
}
However, now the interface has changed into this:
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
throw new NotImplementedException();
}
}
How do I convert the code? :-)
Many thanks!
Gunnar
You could refer to the official github doc to change like below:
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var authAttributes = context.MethodInfo
.GetCustomAttributes(true)
.OfType<AuthorizeAttribute>()
.Select(attr => attr.Policy)
.Distinct();
if (authAttributes.Any())
{
operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
var oAuthScheme = new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
};
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{
[ oAuthScheme ] = authAttributes.ToList()
}
};
}
}
}

How to keep user logged in after browser is closed

Every time I close the browser I need to log in again into this app. It is developed in .NET Core 2.0. I'm trying to let it logged in, like every other regular site.
I checked this post that may be useful, but since the code is quite different from this application I decided to create this post.
This is my security code:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
namespace Petito.Common
{
public interface IActivityContext
{
string ActivityID { get; }
IPrincipal User { get; }
}
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class ActivityIdentity : IIdentity
{
private string _name = null;
[JsonIgnore()]
private bool _isAuthenticated = false;
[JsonIgnore()]
private string _authenticationType = "";
public ActivityIdentity()
{
}
public ActivityIdentity(string name) : this(name, false, "")
{
}
internal ActivityIdentity(string name, bool isAuthenticated, string authenticationType)
{
this._name = name;
this._isAuthenticated = isAuthenticated;
this._authenticationType = authenticationType;
}
public string Name { get => _name; }
public bool IsAuthenticated { get => _isAuthenticated; }
public string AuthenticationType { get => _authenticationType; }
public static ActivityIdentity Unathenticated => new ActivityIdentity();
}
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class ActivityPrincipal : IPrincipal
{
private ActivityIdentity _activityIdentity = null;
private string[] _roles = null;
public ActivityPrincipal() : this(ActivityIdentity.Unathenticated, null)
{
}
public ActivityPrincipal(ActivityIdentity activityIdentity, params string[] roles)
{
_activityIdentity = activityIdentity;
_roles = roles;
}
public ActivityIdentity Identity => _activityIdentity;
IIdentity IPrincipal.Identity => _activityIdentity;
public bool IsInRole(string role)
{
if (_roles != null && _roles.Length > 0)
{
return _roles.Contains(role);
}
return false;
}
}
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class ActivityContext : IDisposable, IActivityContext
{
private string _activityID = Guid.NewGuid().ToString();
private DateTime _startDate = DateTime.UtcNow;
private DateTime? _endDate = null;
private ActivityPrincipal _activityPrincipal = null;
public ActivityContext() : this(null)
{
}
public ActivityContext(IPrincipal principal)
{
_activityPrincipal = Convert(principal);
}
private ActivityPrincipal Convert(IPrincipal principal)
{
if (principal == null)
{
return new ActivityPrincipal();
}
var activityPrincipal = principal as ActivityPrincipal;
if (activityPrincipal != null)
{
return activityPrincipal;
}
var claimsPrincipal = principal as ClaimsPrincipal;
if (claimsPrincipal != null)
{
var roles = claimsPrincipal.Claims.Select(x => x.Value);
var p = new ActivityPrincipal(
new ActivityIdentity(claimsPrincipal.Identity.Name, claimsPrincipal.Identity.IsAuthenticated, claimsPrincipal.Identity.AuthenticationType)
, roles.ToArray()
);
return p;
}
throw new NotSupportedException($"Converting {principal.GetType()} not supported");
}
public void Dispose()
{
if (!_endDate.HasValue)
{
_endDate = DateTime.UtcNow;
}
}
public string ActivityID { get => _activityID; }
public DateTime StartDate { get => _startDate; }
public DateTime? EndDate { get => _endDate; }
public IPrincipal User
{
get
{
return _activityPrincipal;
}
}
}
}
Of course, I'll still try to figure out what's wrong with the code. Please if you need another part of the code other from that I posted let me know.
Thanks!

Custom model binder with inheritance using Web API and RavenDB

I'm developing a simple web app where I need to bind all types implementing and interface of a specific type. My interface has one single property like this
public interface IContent {
string Id { get;set; }
}
a common class using this interface would look like this
public class Article : IContent {
public string Id { get;set; }
public string Heading { get;set; }
}
to be clean here the article class is just one of many different classes implementing IContent so therefor I need a generic way of storing and updating these types.
So in my controller I have the put method like this
public void Put(string id, [System.Web.Http.ModelBinding.ModelBinder(typeof(ContentModelBinder))] IContent value)
{
// Store the updated object in ravendb
}
and the ContentBinder
public class ContentModelBinder : System.Web.Http.ModelBinding.IModelBinder {
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) {
actionContext.ControllerContext.Request.Content.ReadAsAsync<Article>().ContinueWith(task =>
{
Article model = task.Result;
bindingContext.Model = model;
});
return true;
}
}
The code above does not work because it does not seem to get hold of the Heading property even though if I use the default model binder it binds the Heading correctly.
So, in the BindModel method I guess I need to load the correct object from ravendb based on the Id and then update the complex object using some kind of default model binder or so? This is where I need some help.
Marcus, following is an example which would work fine for both Json and Xml formatter.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Runtime.Serialization;
using System.Web.Http;
using System.Web.Http.SelfHost;
namespace Service
{
class Service
{
private static HttpSelfHostServer server = null;
private static string baseAddress = string.Format("http://{0}:9095/", Environment.MachineName);
static void Main(string[] args)
{
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
config.Routes.MapHttpRoute("Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
try
{
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("Service listenting at: {0} ...", baseAddress);
TestWithHttpClient("application/xml");
TestWithHttpClient("application/json");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Exception Details:\n{0}", ex.ToString());
}
finally
{
if (server != null)
{
server.CloseAsync().Wait();
}
}
}
private static void TestWithHttpClient(string mediaType)
{
HttpClient client = new HttpClient();
MediaTypeFormatter formatter = null;
// NOTE: following any settings on the following formatters should match
// to the settings that the service's formatters have.
if (mediaType == "application/xml")
{
formatter = new XmlMediaTypeFormatter();
}
else if (mediaType == "application/json")
{
JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
formatter = jsonFormatter;
}
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(baseAddress + "api/students");
request.Method = HttpMethod.Get;
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
HttpResponseMessage response = client.SendAsync(request).Result;
Student std = response.Content.ReadAsAsync<Student>().Result;
Console.WriteLine("GET data in '{0}' format", mediaType);
if (StudentsController.CONSTANT_STUDENT.Equals(std))
{
Console.WriteLine("both are equal");
}
client = new HttpClient();
request = new HttpRequestMessage();
request.RequestUri = new Uri(baseAddress + "api/students");
request.Method = HttpMethod.Post;
request.Content = new ObjectContent<Person>(StudentsController.CONSTANT_STUDENT, formatter);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
Student std1 = client.SendAsync(request).Result.Content.ReadAsAsync<Student>().Result;
Console.WriteLine("POST and receive data in '{0}' format", mediaType);
if (StudentsController.CONSTANT_STUDENT.Equals(std1))
{
Console.WriteLine("both are equal");
}
}
}
public class StudentsController : ApiController
{
public static readonly Student CONSTANT_STUDENT = new Student() { Id = 1, Name = "John", EnrolledCourses = new List<string>() { "maths", "physics" } };
public Person Get()
{
return CONSTANT_STUDENT;
}
// NOTE: specifying FromBody here is not required. By default complextypes are bound
// by formatters which read the body
public Person Post([FromBody] Person person)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, this.ModelState));
}
return person;
}
}
[DataContract]
[KnownType(typeof(Student))]
public abstract class Person : IEquatable<Person>
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
// this is ignored
public DateTime DateOfBirth { get; set; }
public bool Equals(Person other)
{
if (other == null)
return false;
if (ReferenceEquals(this, other))
return true;
if (this.Id != other.Id)
return false;
if (this.Name != other.Name)
return false;
return true;
}
}
[DataContract]
public class Student : Person, IEquatable<Student>
{
[DataMember]
public List<string> EnrolledCourses { get; set; }
public bool Equals(Student other)
{
if (!base.Equals(other))
{
return false;
}
if (this.EnrolledCourses == null && other.EnrolledCourses == null)
{
return true;
}
if ((this.EnrolledCourses == null && other.EnrolledCourses != null) ||
(this.EnrolledCourses != null && other.EnrolledCourses == null))
return false;
if (this.EnrolledCourses.Count != other.EnrolledCourses.Count)
return false;
for (int i = 0; i < this.EnrolledCourses.Count; i++)
{
if (this.EnrolledCourses[i] != other.EnrolledCourses[i])
return false;
}
return true;
}
}
}
I used #kiran-challa solution and added TypeNameHandling on Json media type formatter's SerializerSettings.

Why WF4 Constraints are not working with Activity and CodeActivity parent's types

I want to set constraint to activity to prevent adding it to some other activities.
I have problem with GetParentChain I think. I did everything like in msdn samples:
I have three activities: MyActivity, SqlNativeActivity and SqlActivity. This classes look like:
SqlNativeActivity:
public sealed class SqlNativeActivity : BaseNativeActivity
{
public Activity Activity { get; set; }
protected override void Execute(NativeActivityContext context)
{
}
}
public abstract class BaseNativeActivity : NativeActivity
{
protected ActivityConstraintsProvider ActivityConstraintsProvider;
protected abstract override void Execute(NativeActivityContext context);
}
SqlActivity:
public sealed class SqlActivity : BaseActivity
{
public Activity Activity { get; set; }
}
public abstract class BaseActivity : Activity
{
protected ActivityConstraintsProvider ActivityConstraintsProvider;
}
MyActivity:
public sealed class MyActivity : BaseActivity
{
public MyActivity()
{
ActivityConstraintsProvider = new ActivityConstraintsProvider();
ActivityConstraintsProvider.AddNotAcceptedParentActivity(typeof(SqlActivity));
ActivityConstraintsProvider.AddNotAcceptedParentActivity(typeof(SqlNativeActivity));
base.Constraints.Add(ActivityConstraintsProvider.CheckParent());
}
}
And I wrote ActivityConstraintsProvider in which I define List with not accepted parent types.
ActivityConstraintsProvider:
public class ActivityConstraintsProvider
{
private List<Type> _notAcceptedParentActivity;
public void AddNotAcceptedParentActivity(Type type)
{
if (_notAcceptedParentActivity == null)
_notAcceptedParentActivity = new List<Type>();
_notAcceptedParentActivity.Add(type);
}
public Constraint CheckParent()
{
var element = new DelegateInArgument<Activity>();
var context = new DelegateInArgument<ValidationContext>();
var result = new Variable<bool>();
var parent = new DelegateInArgument<Activity>();
var con = new Constraint<Activity>
{
Body = new ActivityAction<Activity, ValidationContext>
{
Argument1 = element,
Argument2 = context,
Handler = new Sequence
{
Variables =
{
result
},
Activities =
{
new ForEach<Activity>
{
Values = new GetParentChain
{
ValidationContext = context
},
Body = new ActivityAction<Activity>
{
Argument = parent,
Handler = new If()
{
Condition = new InArgument<bool>((env) => _notAcceptedParentActivity.Contains(parent.Get(env).GetType())),
Then = new Assign<bool>
{
Value = true,
To = result
},
}
}
},
new AssertValidation
{
Assertion = new InArgument<bool> { Expression = new Not<bool, bool> { Operand = result } },
Message = new InArgument<string> ("Decide can't be in Sql"),
}
}
}
}
};
return con;
}
}
And finally Main:
class Program
{
static void Main()
{
ValidationResults results;
Activity wf3 = new SqlActivity
{
Activity = new Sequence()
{
Activities =
{
new MyActivity
{
}
}
}
};
results = ActivityValidationServices.Validate(wf3);
Console.WriteLine("WF3 (SqlActivity):");
PrintResults(results);
//----------------------------------------------------------------
Activity wf4 = new SqlNativeActivity
{
Activity = new Sequence()
{
Activities =
{
new MyActivity
{
}
}
}
};
results = ActivityValidationServices.Validate(wf4);
Console.WriteLine("WF4 (SqlNativeActivity):");
PrintResults(results);
//----------------------------------------------------------------
}
static void PrintResults(ValidationResults results)
{
Console.WriteLine();
if (results.Errors.Count == 0 && results.Warnings.Count == 0)
{
Console.WriteLine(" No warnings or errors");
}
else
{
foreach (ValidationError error in results.Errors)
{
Console.WriteLine(" Error: " + error.Message);
}
foreach (ValidationError warning in results.Warnings)
{
Console.WriteLine(" Warning: " + warning.Message);
}
}
Console.WriteLine();
}
}
And the problem is that if my sql activity is inherites from System.Activities.NativeActivity (SqlNativeActivity) constraints are working very well, but if I define constraints and parent is activity inherites from System.Activities.Activity or System.Activities.CodeActivity constraints validation is not working at all.
Anybody can help me with my problem?
Thank you in advance :)
if you create a custom activity (inheriting from System.Activities.CodeActivity), your validation should be done at CacheMetaData:
protected override void CacheMetadata(CodeActivityMetadata metadata)
{
//Validate here
base.CacheMetadata(metadata);
}