Validations in Webpapi

2

I'm starting to study webapi with knockout , using a classe f% as an example I made my model , in knockout I made the list and include it, in my classe I have decorated the attributes with some data annotations , in this part enter my doubt, I know that with knockout I can do enough validations on the client side, but I also want to have these validations on the server. What is the best way to show server side errors when using webapi ?

Follow the code below for what I'm ready to do!

Model

public class Noticia
    {
        public int Id { get; set; }

        [Required(ErrorMessage = "Campo obrigatório!")]
        public string Titutlo { get; set; }

        [DataType(DataType.Date)]
        [Required(ErrorMessage = "Campo obrigatório!")]
        public DateTime DataCadastro { get; set; }

        [Required(ErrorMessage = "Campo obrigatório!")]
        public string Conteudo { get; set; }
    }

Controller

public IQueryable<Noticia> GetNoticias()
{
    return _db.Noticias;
}

[HttpPost]
[ResponseType(typeof(Noticia))]
public IHttpActionResult PostNoticia(Noticia noticia)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    if (noticia == null)
    {
        return BadRequest();
    }

    _db.Noticias.Add(noticia);
    _db.SaveChanges();

    return CreatedAtRoute("DefaultApi", new { id = noticia.Id }, noticia);
}

** VIEW **

<div class="lista-noticias">
    <h2>Lista de Notícias</h2>
    <hr />

    <table id="newsTable" class="table table-condensed">
        <thead>
            <tr>
                <th>Titulo</th>
                <th>Data de Cadastro</th>
            </tr>
        </thead>
        <tbody data-bind="foreach: noticias">
            <tr>
                <td>
                    <span data-bind="text: titutlo"></span>
                </td>
                <td>
                    <span data-bind="text: dataCadastro"></span>
                </td>
            </tr>
        </tbody>
    </table>
</div>

<div class="cadastra-noticias">

    <form id="AddNoticia">
        <div class="row form-group">
            <input type="hidden" data-bind="value : noticia.id" class="form-control input-lg" />

            <label class="control-label">Título</label>
            <input data-bind="value : NovaNoticia.titutlo" class="form-control input-lg" />

            <label class="control-label">Data Cadastro</label>
            <input data-bind="value : NovaNoticia.dataCadastro" class="form-control input-lg" />

            <label class="control-label">Conteúdo</label>
            <input data-bind="value : NovaNoticia.conteudo" class="form-control input-lg" />

            <input type="button" id="btnAddStudent" class="btn btn-primary" value="Add Noticia" data-bind="click: $root.AddNoticia" />
        </div>
    </form>
</div>

** KnockOut JS **

function noticia(id, titutlo, dataCadastro, conteudo) {
    return {
        id: ko.observable(id),
        titutlo: ko.observable(titutlo),
        dataCadastro: ko.observable(dataCadastro),
        conteudo: ko.observable(conteudo)
    };
}

function NoticiaViewModel() {
    var self = this;

    self.NovaNoticia =
       {
           id: ko.observable(0),
           titutlo: ko.observable("").extend({ required: true }),
           dataCadastro: ko.observable("").extend({ required: true }),
           conteudo: ko.observable("").extend({ required: true })
       };

    self.noticias = ko.observableArray([]);

    $.getJSON("/admin/api/noticiasapi", function (data) {
        self.noticias(data);
    });

    self.AddNoticia = function (model, event) {
        $.post("/admin/api/noticiasapi/PostNoticia", model.NovaNoticia)
            .complete(function (data) {
                self.noticias.push(data);
            }).fail(function (data) {
                $(".list-errors").removeClass("hide");

                //$(".list-errors ul").append("<li>" + data.message + "</li>");
            console.warn(data.responseText);

        });
    };
}

ko.applyBindings(new NoticiaViewModel());
    
asked by anonymous 05.08.2014 / 22:51

1 answer

3

As I researched , there are two ways:

  • Using simple AJAX;
  • Using jQuery;

In addition, on this other article , it is recommended to implement a Filter that returns ModelState to the request caller (an AJAX request opened by jQuery, for example):

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.ModelBinding;

namespace MyApi.Filters
{
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (actionContext.ModelState.IsValid == false)
            {
                actionContext.Response = actionContext.Request.CreateErrorResponse(
                    HttpStatusCode.BadRequest, actionContext.ModelState);
            }
        }
    }
}

The answer will be something like this:

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Date: Tue, 16 Jul 2013 21:02:29 GMT
Content-Length: 331

{
  "Message": "The request is invalid.",
  "ModelState": {
    "noticia": [
      "Required property 'Titulo' not found in JSON. Path '', line 1, position 17."
    ],
    "noticia.Titulo": [
      "The Titulo field is required."
    ],
    "product.Conteudo": [
      "The Conteudo field is required."
    ]
  }
}

The call for validation would look something like this:

ko.validation.rules['remote'] = {
    async: true,
    validator: function ( val, params, callback ) { 
        var defaults = {
            url: '/Noticias',
            type: 'POST',
            success: callback
        };

        var options = $.extend( defaults, params );

        $.ajax( options );

        // Aqui possivelmente você terá que customizar o código, 
        // pra satisfazer o callback e o resto do funcionamento da validação.
    },
    message: 'Default Invalid Message'
};

Your Controller looks like this:

[HttpPost]
[ResponseType(typeof(Noticia))]
public IHttpActionResult PostNoticia(Noticia noticia)
{
    {
        if (ModelState.IsValid)
        {
            _db.Noticias.Add(noticia);
            _db.SaveChanges();

            return CreatedAtRoute("DefaultApi", new { id = noticia.Id }, noticia);

            // return new HttpResponseMessage(HttpStatusCode.OK);
        }
        else
        {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        }
    }
}

I have not tested this code, but this is the path.

    
08.08.2014 / 03:05