I've a hard time trying to inject IEnumerable<IInputFormatters> to other services.
I've registered my own InputFromatter and also I've added JsonFormatters. So, at least there should be 3 input formatters, but when I try to inject IEnumerable<IInputFormatters>, I'm constantly getting null (like there is no formatters at all).
My registration looks like:
services.AddMvcCore(config =>
{
config.InputFormatters.Insert(0, new UserContextFormatter());
config.ModelBinderProviders.Insert(0, new ModelBinderProvider());
})
.AddAuthorization()
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>())
.AddJsonOptions(opt =>
{
opt.SerializerSettings.Formatting = Formatting.Indented;
opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
opt.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
})
.AddJsonFormatters()
.AddApiExplorer();
Seems like something easy and stupid, but I'm not good enough to get it. Any ideas?
Thanks!
For IEnumerable<IInputFormatters>, it is not registered as service, so you could not resolve it or access it from Dependency injection.
For InputFormatters or ModelBinderProviders, they are appended to Action<MvcOptions> setupAction, so you could access them from IOptions<MvcOptions>.
Try code below:
public class HomeController : ControllerBase
{
private readonly MvcOptions _options;
public HomeController(IOptions<MvcOptions> options)
{
_options = options.Value;
var inputFormatters = _options.InputFormatters;
var outputFormatters = _options.OutputFormatters;
var modelBinderProviders = _options.ModelBinderProviders;
}
Related
I'm struggling to make the fields of my request DTOs case insensitive.
export class ExampleDto {
dateOfBirth?: string
}
Now I want to accept
{ "dateofbirth": "19880101" }
{ "dateOfBirth": "19880101" }
{ "DATEOFBIRTH": "19880101" }
My first thought was to implement a middleware which just looks at the incoming body and "extends it" with lower & upper case mappings for all incoming fields.
But that doesn't meet my requirements due to camel case, which I definitely want to keep as the default.
Any ideas on how to do this?
You could create a custom Pipe where you try the different options and finally return the Dto instance:
export class CaseInsensitiveExampleDtoPipe implements PipeTransform{
transform(body: any, metadata: ArgumentMetadata): ExampleDto {
const dto = new ExampleDto();
dto.dateOfBirth = body.dateOfBirth || body.dateofbirth || body.DATEOFBIRTH;
return dto;
}
In your controller you can then use it as follows:
#UsePipes(new CaseInsensitiveExampleDtoPipe())
async postNewExample(#Body() exampleDto: ExampleDto) {
// ...
}
Since JavaScript properties start existing after their initialization, you cannot "see" the definition of dateOfBirth?: string and therefor you won't be able to match it against the received JSON.
A possible solution for that is to enforce the creation of the properties of all of your DTO's with a constructor:
export class ExampleDto {
dateOfBirth: string
constructor(dateOfBirth: string){
this.dateOfBirth = dateOfBirth;
}
}
Then, you'll be able to iterate over the ExampleDto's properties and match them with a pipe (the received type can be derived from metadata):
#Injectable()
export class IgnoreCasePipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
const dto = new metadata.metatype;
const dtoKeys = Object.getOwnPropertyNames(dto);
Object.keys(value).forEach(key => {
const realKey = dtoKeys.find(dtoKey => dtoKey.toLocaleLowerCase() === key.toLocaleLowerCase());
if (realKey) {
dto[realKey] = value[key];
}
});
return dto;
}
}
Either inject it globally in main.ts or wherever it's needed - just bear in mind that you'll need to create a constructor for each DTO.
Note: this would work for a single-level class. If you want to support something like people: PersonDto[] in your classes then you'll need to recursively find all of the nested keys and match them - something like this.
I have a function that is in a class :
Simplified version :
export class Button {
getAttributes(el) {
//random code that was removed for simplicity
return dataAttrs;
}
}
I was wondering how do I test this in Jest.
Here is what worked for me :
test('get attributes on element', () => {
let button= new Button();
var element = document.createElement('a');
element.setAttribute('href', 'https://www.google.ca/');
element.innerHTML = 'Test';
expect(breadcrumb.getAttributes(element)).toBe('Hello');
});
if there is simple class like the one that u define u can do:
it('We can check the class constructor', () => {
const classObject = new classObject();
expect(classObject ).toHaveBeenCalledTimes(1);
});
and use whatever the methods that Jest have.
But if there are complex classes and methods that ones are dependent from others i suggest you to read this and you can automatize it or can do it manually, mock the dependences and test it out.
I have more than one endpoints.I am able to apply common filters on endpoints using finagle filter.But now I want to apply a filter on a specific endpoint.
How can I achieve this?
I had a similar question (for basic authentication filtering) that popped up while playing with redbubble's finch template which I partially solved in the following way:
class AuthenticatedEndpoint[A](e: Endpoint[A]) extends Endpoint[A] { self =>
final def apply(mapper: Mapper[A]): Endpoint[mapper.Out] = mapper(self)
final def apply(input: Input): Endpoint.Result[A] =
if (checkSession(input.request)) {
e(input)
} else {
// TODO return something meaningful to the caller (if possible?)
EndpointResult.Skipped
}
}
object AuthenticatedEndpoint {
def validSession[A](e: Endpoint[A]): Endpoint[A] = new AuthenticatedEndpoint(e)
}
(with checkSession returning true if all is well with the request). Then my api is defined as:
val api = "v1" :: loginApi :+: validSession(peopleApi :+: healthApi :+: adminApi)
This works well in the sense that requests without a session won't have access to the endpoints passed to validSession, but I have yet to find an easy way to return an error message to the caller, and I'd be curious to know if I chose the right path here.
This is how I got around it. It's probably not ideal but works.
class AuthenticatedEndpoint[A](e: Endpoint[A])(implicit auth: Request => Boolean) extends Endpoint[A] { self =>
final def apply(mapper: Mapper[A]): Endpoint[mapper.Out] = mapper(self)
final def apply(input: Input): Endpoint.Result[A] =
if (auth(input.request)) {
e(input)
} else {
EndpointResult.Matched[Nothing](input, Rerunnable( Unauthorized(new Exception(s"Authentication Failed."))) )
}
}
object AuthenticatedEndpoint {
def validSession[A](e: Endpoint[A]): Endpoint[A] = new AuthenticatedEndpoint(e)
}
I have a little problem resolving getting SilverStripe 3.1 Fulltextsearchable running good for my usage. I retrieve some informations from Member dataobject and I create Links and Titles to show them on Page_search.ss template.
There is my code working but... bad search filtering :
public function results($data, $form){
$data = $_REQUEST;
$query = htmlspecialchars($data['Search'], ENT_QUOTES,'UTF-8');
$PageMembres = Member::get()->filter('NomOrganisme',$query);
$searchresults = new ArrayList();
foreach($PageMembres as $membre) {
if ($membre->Type==1) { $dir="repertoire-culturel/organismes-entreprises/details/"; }
if ($membre->Type==2) { $dir="repertoire-culturel/individus-artistes/details/"; }
$searchresults->push(
array( "Title" => $membre->NomOrganisme,
"link" => $membre->ID,
"Link" => Director::BaseURL().$dir.$membre->ID,
"URL" => $membre->ID,
)
);
}
if($searchresults){
$data['Results'] = $searchresults;
} else {
$data['Results'] = '';
}
$data['Title'] = 'Résultat(s) de recheche';
return $this->customise($data)->renderWith(array('Page_results','Page'));
}
So I that point, I need to change :
$PageMembres = Member::get()->filter('NomOrganisme',$query);
For a more complexe research like :
$PageMembres = DataObject::get("Member","MATCH (NomOrganisme,FirstName,Surname,Description) AGAINST ('$query' IN BOOLEAN MODE)");
What I have missed with the complexe query? Why It doesn't works?
Thanks for reply!
I think we can't use MATCH query on DataObject Member. There is my complexe working code that I use and works :
$PageMembres = Member::get()->where("
FirstName LIKE '%$query%' OR
Surname LIKE '%$query%' OR
Description LIKE '%$query%' OR
NomOrganisme LIKE '%$query%'");
The Data & Security guide at Parse.com describes how to control access on class and object level. I am looking for a way to restrict write permissions on certain properties of a class for all users. How can this be achieved?
My idea would be to use a One-to-One relationship and restrict the access on the related class. However, this doesn't feel like the canonical way...
The easiest way to do this is to use cloud code. Here is how you could do it :
Parse.Cloud.beforeSave("YourObject", function(request, response)
{
// Find a way to decide if writing is allowed.
var writingForbidden = (request.master === false);
if (writingForbidden)
{
var readOnlyProperties = ["property1", "property2", "property3", "..."];
var dirtyProperties = request.object.dirtyKeys();
for (i = 0 ; i < dirtyProperties.length ; i++) {
var dirtyProperty = dirtyProperties[i];
if (readOnlyProperties.indexOf(dirtyProperty) > -1) {
return response.error("Trying to change a readonly property : " + dirtyProperty);
}
}
}
return response.success();
}