Author Archives: Anna Yafi

About Anna Yafi

C# developer. Asp.Net mvc full stack developer. Also found of any new technologies : typescript, cordova, xamarin... whichever interesting one :)

ASP.NET Core : Overriding controller AuthorizeAttribute for just one action

Standard

In Asp.Net Core, creating custom authorize attributes is over. You’d better deal with policies now. If you want to override the controller AuthorizeAttribute for just one action with a stronger policy, nothing simpler :

[Authorize]
public class AuthorizedController : Controller
{
    [HttpGet("do-authorized-stuff/{id}")]
    public IActionResult Whatever(int id)
    { }

    [Authorize(Consts.AdminOnly)]
    [HttpGet("do-admin-stuff/{id}")]
    public IActionResult WhateverAdminStuff(int id)
    {
    }

}

But what if you want to override it with a weaker policy ? For example you want to override the admin policy just for one action which would be available to any authenticated user like so :

[Authorize(Consts.AdminOnly)]
public class AuthorizedController : Controller
{

    [Authorize] //admin policy is still applied :o(
    [HttpGet("do-authorized-stuff/{id}")]
    public IActionResult Whatever(int id)
    { }

    [HttpGet("do-admin-stuff/{id}")] //admin policy is applied
    public IActionResult WhateverAdminStuff(int id)
    { }

This won’t work as policies are accumulated, in other words it’s an AND not an OR.
Still, Asp.Net Core has a lot of possibilities and you could simply do in Startup.cs file :

services.AddAuthorization(options =>
{
    var simplyAuthenticated = new AuthorizationPolicy(new DenyAnonymousAuthorizationRequirementOverrideOthers().Yield(), new List<string>());
    options.AddPolicy(name: PolicyConsts.AuthenticatedOnlyOverridePolicyName, policy: simplyAuthenticated);
    options.AddPolicy(name: PolicyConsts.Admin, configurePolicy: policy => policy.RequireAssertion(e =>
    {
        if (e.Resource is AuthorizationFilterContext afc)
        {
            var noPolicy = afc.Filters.OfType<AuthorizeFilter>().Any(p => p.Policy.Requirements.Count == 1 && p.Policy.Requirements.Single() is DenyAnonymousAuthorizationRequirementOverrideOthers);
            if (noPolicy)
                return true;
        }
        return e.User.IsInRole(Consts.Admin);
    }));

}

and here’s the custom DenyAnonymousAuthorizationRequirementOverrideOthers :


namespace Whatever
{
    using Microsoft.AspNetCore.Authorization.Infrastructure;

    public class DenyAnonymousAuthorizationRequirementOverrideOthers : DenyAnonymousAuthorizationRequirement
    { }
}

 

and here’s the controller :


[Authorize(PolicyConsts.AdminOnly)]
public class AuthorizedController : Controller
{

    [Authorize(PolicyConsts.AuthenticatedOnlyOverride)]
    [HttpGet("do-authorized-stuff/{id}")]//admin policy is bypassed thanks to our startup.cs code
    public IActionResult Whatever(int id)
    { }

    [HttpGet("do-admin-stuff/{id}")] //admin policy is applied coming from controller
    public IActionResult WhateverAdminStuff(int id)
    { }
}

And you can add any custom policy you want and make it override others in the RequireAssertion Func of other policies.

Hope it helps, see ya !

Advertisements

TagHelpers : using the post method with html anchor tags

Standard

Want to make an anchor which would issue a post call to the server rather than a get ?

post anchor tag

instead of writing the ugly :

<form asp-controller="Account" asp-action="Logout" method="post" id="logout-form"></form>

 <a href="javascript:document.getElementById('logout-form').submit()"></a>

Why not use a tag helper to generate this behind the scenes and keep your html clean ? Here’s mine, I made it simple, your anchor must have an id, a href and a asp-post attribute to work with it.

    [HtmlTargetElement("a", Attributes = ForAttributeName + ",id,href")]
    public class PostAnchorTagHelper : TagHelper
    {
        private const string ForAttributeName = "asp-post";
        private IHtmlGenerator _generator;

        public PostAnchorTagHelper(IHtmlGenerator generator)
        {
            _generator = generator;
        }

        [HtmlAttributeName(ForAttributeName)]
        public string For { get; set; }

        [HtmlAttributeNotBound]
        [ViewContext]
        public ViewContext ViewContext { get; set; }

        public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            var href = context.AllAttributes["href"].Value.ToString();
            var id = context.AllAttributes["id"].Value.ToString();
            output.Attributes.RemoveAll("href");
            var form = new TagBuilder("form");
            form.Attributes.Add("action", href);
            form.Attributes.Add("method", "post");
            form.Attributes.Add("asp-antiforgery", "true");
            var idForm = id + "-form";
            form.Attributes.Add("id", idForm);
            var antiforgeryTag = _generator.GenerateAntiforgery(ViewContext);
            if (antiforgeryTag != null)
            {
                form.InnerHtml.AppendHtml(antiforgeryTag);
            }
            output.Attributes.Add("href", $"javascript:document.getElementById('{idForm}').submit()");
            output.PostElement.AppendHtml(form);
            return base.ProcessAsync(context, output);
        }
    }

Now, just write :

<a id="logout" href="@Url.Action("Logout", "Account")" asp-post="true"></a>

And you’re good to go !

Localizing validation messages in asp.net core : fallback on shared resources if not found

Standard

Right now in asp.net core, when you want to localize your validation messages, you have to create a resource file with the exact same name as your viewmodel, as explained here : https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization#dataannotations-localization

What if you want to keep this smart mechanism but still get a fallback to a shared resource file ? For example, let’s say you want to have the message “This field is absolutely required please !” instead of the standard message, for all required fields in all your viewmodels. You obviously don’t want to specify this message in every localized resource file named like your viewmodel.

Here’s a basic solution. In the startup.cs file, add something like :

services.AddMvc().AddDataAnnotationsLocalization(o =>
o.DataAnnotationLocalizerProvider = (modelType, stringLocalizerFactory) =>
{
   var sl = stringLocalizerFactory.Create(modelType);
   var shared = stringLocalizerFactory.Create(typeof(SharedResources));
   var ezSl = new MyDataAnnotations.ResourceManagerStringLocalizer(sl, shared);
   return ezSl;
})

And this is how your class MyDataAnnotations.ResourceManagerStringLocalizer could look like :

Read the rest of this entry

Beware of IEnumerable with Entity Framework

Standard

Sometimes you want to build a generic data access layer out of your entity framework concrete context, and you want to use the precious generic method on the DbContext such as the generic Set(). If it can spare you some time… Beware than when you do :

         public IEnumerable<T> Get<T>() where T : class
        {
            return _context.Set<T>();
        }

When the function returns, your query is already materialized, the query to the database has been made ! Because the Get function’s return type, IEnumerable, implies an implicit cast to get it from a DbSet. EF is probably making a ToList() inside to transform to IEnumerable, and thus, making the roundtrip to database and materializing objects.

To keep a lazy set, it’s better to switch to  :

       public IQueryable<T> Get<T>() where T : class
        {
            return _context.Set<T>();
        }

 

Charger des scripts dans une vue partielle

Standard

En ASP.NET MVC,  il arrive que l’on veuille écrire ou référencer des scripts depuis une vue partielle, afin de déléguer l’entière responsabilité de certains scripts et de leur fonctionnement à ce bout de vue uniquement. Par exemple, une vue partielle destinée à de la conversation instantanée, à du « chat », présentera tous les éléments UI nécessaires à l’envoi et à la réception de messages instantanés si la personne est authentifiée et s’occupera également de s’assurer que les bons scripts, tels que SignalR par exemple, ont été chargés et exécutés en vue du bon fonctionnement du chat.

Ces scripts nécessitent souvent que d’autres scripts aient été chargés au préalable, comme JQuery par exemple. Malheureusement, une vue partielle se situe souvent en milieu de document et les scripts de base, eux, souvent juste avant la balise de fermeture du body, afin de ne pas bloquer le rendu de la page et de conserver de bonnes performances. Sachant qu’ils se chargent et s’exécutent dans l’ordre de leur référencement, les scripts situés dans la vue partielle ne fonctionneront pas car les dépendances n’auront pas encore été chargées.

Ce problème se résout facilement dans une vue basique car il est possible de redéfinir une section en ASP.NET MVC : le développeur peut redéfinir la section « Scripts » qui se situerait après les scripts de base de fin de body. Mais dans une vue partielle, il est impossible de redéfinir une section. Ainsi, un script présent dans une vue partielle nécessitant JQuery risque de planter en disant que $ est « undefined ».

Read the rest of this entry

Google Maps sous Android : garantir de bonnes performances

Standard

Article publié dans le magazine Programmez ! – Juillet 2014 – N° 176

La présence d’une carte est souvent nécessaire dans les applications Android, notamment des applications liées au transport, ou encore à certains réseaux sociaux indiquant où se trouvent des contacts. L’utilisateur est alors amené à parcourir la carte et à jouer avec le zoom pour situer des repères qui l’intéressent : un ami, un restaurant, un itinéraire… Dès que de nombreux repères sont à placer sur la carte, celle-ci risque d’être ralentie. Mais si la carte n’est pas fluide et se dessine par saccades, l’utilisateur peut vite être découragé et chercher une autre application. Quelles règles élémentaires respecter alors afin de garantir une bonne réactivité de la carte Google ?

Depuis la deuxième version de l’API Google Maps, fonctionnant avec les services Google Play, il est beaucoup plus simple de gérer les repères sur la carte grâce aux événements disponibles sur la classe centrale com.google.android.gms.maps.GoogleMap.

Read the rest of this entry

Gestion des erreurs en ASP.NET MVC

Standard

Article publié dans le magazine Programmez ! – Avril 2014 – N° 173

Lors de la conception d’une application web, gérer le comportement du système en cas d’erreur est important et ne devrait pas être laissé au hasard. D’une part, visualiser une page système peu accueillante, non stylisée, et loin des couleurs du site n’est pas toujours agréable pour l’utilisateur qui vient en plus de recevoir une erreur. D’autre part, si certains paramétrages ne sont pas effectués, l’utilisateur pourrait avoir accès aux détails techniques de l’exception. Un visiteur mal intentionné pourrait se servir de ces détails pour accumuler des connaissances sur la structure technique du site et trouver plus facilement une faille de sécurité à exploiter. Ainsi, il appartient à l’équipe de réalisation du site de déterminer en amont le niveau de détails d’erreur à délivrer à l’utilisateur, les codes d’erreur HTTP à renvoyer en fonction des situations et les pages d’erreur qui seront affichées. En somme, il s’agit de décider d’un comportement applicatif en cas d’erreur qui soit uniformément suivi au cours des développements.

ASP.NET MVC offre de nombreuses solutions pour gérer une exception de manière centralisée et rediriger vers une ressource en particulier. Gérer les erreurs peut donc se faire de plusieurs façons et peut s’adapter à divers scénarios. Ces différentes manières seront exposées au cours de cet article, du niveau le plus global à celui le plus fin.

Read the rest of this entry

How to display little temporary javascript messages to the user ?

Standard

Hello everyone,

Today, I’ll talk about displaying little notification messages at the bottom of a web page, and how to make them appear and vanish after a few seconds in a customizable way, thanks to JQuery. Let’s say we need to display messages that would stack up against each other, and each would appear and disappear after a specified time. We want to :

–          Style the notifications (error, validation…)
–          Style the whole notification template and put whatever we want in it
–          Notifications should anchor to the bottom of the page, wherever we’re scrolling at.
–          All this within a jquery plugin ?

To ease our task, we’d rather use jquery template.

First, refer the scripts you need at the end of the page to prevent them from slowing html rendering :

  <script src="Scripts/jquery-1.9.1.js"></script>
    <script src="Scripts/jquery-tmpl.js"></script>
    <script src="Scripts/notificationMaker.js"></script> <!--our plugin-->

Then create your page. For the sake of the demo, we add 3 buttons, one for displaying negative messages, one for good messages, the last one for custom templated messages. We add a long text excerpt to check that scrolling doesn’t affect our notification messages anchor.

 <div id="whole">
            <div id="buttons">
                <textarea id="myMessage"></textarea>
                <br />
                <button id="notification-negative">post alert</button>
                <button id="notification-positive">post good message</button>
                <br />

                <button id="templated-notification">post custom message</button>
            </div>
            <div id="content">
                    "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."
            1914 translation by H. Rackham

             "... and so on ... (big text to show even when scrolling notification messages stay put"
            </div>
        </div>

Then write the script that will use our notification jquery plugin. I just wrote an example, but you can use it any way you want. First function will use a simple css class for styling good messages. Second function will use a different css class for errors then specify how many milliseconds the message will appear.

<script type="text/javascript">
        $(document).ready(function () {
            $("#notification-positive").click(function () {
                var value = $("#myMessage").val();
                $.postMessage(value,
                    {
                        cssClass: "notification-message",
                    })
                ;
            });
            $("#notification-negative").click(function () {
                var value = $("#myMessage").val();
                $.postMessage(value,
                    {
                        cssClass: "notification-error",
                        time:4000,
                    })
                ;
            });
       });
    </script>

A third function specify a custom template, giving its selector.

$("#templated-notification").click(function () {
                var value = $("#myMessage").val();
                $.postMessage(value,
                    {
                        template: "#my-message-template",
                    });
            });

And here’s the template

 <script id="my-message-template" type="text/html">
        <div class="templated-part">
            <p>{{= Message }}</p>
        </div>
    </script>

Of course you could build the template the way you want, with pictures, other div, span or whatever inside it. Just evaluate the “Message” variable wherever you want to show the text message.

Now let’s show the interesting part, the plugin part  with all comments :

(function ($) {
    var notificationMaker = {
        messageArea: null,
        init: function () { //just once at the beginning to insert the message area once into the DOM
            if (notificationMaker.messageArea)
                return;
            messageArea = document.createElement('div');
            $(messageArea).addClass("notification-area"); //style the notification area in stylesheet if you don't want it that way
            $("body").append(messageArea);
        },
        //method that shows the messages for a specific time and with animations
        showMessage: function (elm, time) {
            $(elm).slideToggle();//or use whatever animation you want
            setTimeout(function () {
                $(elm).slideToggle({
                    complete: function () {
                        messageArea.removeChild(elm); //important, remove the element from DOM so that DOM doesn't grow too much
                    }
                });
            }, time);
        },
        methods: {
            //options : cssClass, custom template, time to display the message
            postMessage: function (message, options) {
                var element = null;
                options = (!options) ? {} : options;
                var time = (options.time) ? options.time : 3000; //sets a default time if none specified
                if (!options.template) { //if no template, that's gonna be a paragraph
                    element = document.createElement('p');
                    if (options.cssClass) //if there's a specified css class
                        $(element).addClass(options.cssClass);
                    $(element).text(message); //sets the text
                }
                else {
                    element = $(options.template).tmpl({ Message: message })[0]; //apply a jquery template,
                    //take the first of the array a jquery template will return an array
                    //we need an object only to remove it from DOM later
                }
                $(element).hide();
                $(messageArea).append(element);
                notificationMaker.showMessage(element, time);
                return this;
            },
        }
    };

    //add the plugin method to jquery methods, beware not to replace any jquery native methods.
    $.postMessage = function(method) {
        var methods = notificationMaker.methods;
        if (typeof method === 'string') {
            if (method !== "")
                return methods.postMessage.apply(this, arguments);
            else return this;
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.notificationMaker');
        }
    };
    notificationMaker.init();

})(jQuery);

That way, it is clipped to the page’s bottom, no matter if you scroll the page, thanks to a custom JQuery plugin.

Here’s the zipped project if you want the whole thing with css :

Client side notifications sample

Enjoy 😉

My changes in kendo external templates are ignored by IE

Standard

Hi guys,
Again a very simple tip on kendo : if you’re using kendo external templates, you might be wondering why your recent changes aren’t reflected, or even why recently new added templates can’t be found when running your site within Internet Explorer.

IE in particular will cache your kendo template files in folder Temporary Internet Files. Feel free to empty that folder to get your last modifications !

Kendo autocomplete box and server filtering

Standard

Hello all,
A very simple thought today but as it took me some time to figure it out, I thought that little post could make you spare some.

I used the autocomplete box from kendo UI bound with a remote datasource. Based on the user input, server returned a set of matching words, processing quotes for example for a google-like exact search. But the autocomplete box kept filtering client-side too, looking for quotes in the results set and filtering all my server results…. I finally figured out that setting “serverFiltering = true” on the datasource itself stopped the client-side filtering !
Happy coding !

var dataSource = new kendo.data.DataSource({
      transport: {
         read: { url : "http....",
        },
      success: function (response) {
         o.success(response);
       }
 },
 serverFiltering: true, //set it to true to stop client-side filtering
 total: 5, //five results only
 optionLabel: "Type in a...",
 });

myAutoComplete.kendoAutoComplete({
 dataSource: dataSource,
 dataTextField: "toto",
 dataValueField: "titi",
 …
 )} ;