Validating a Domain or Service Method
Some things that stuck out to me.  FWIW.

//NOTE: for me, this validator can only describe what went wrong without
//        giving you a specific way to handle each kind of thing that happened.
//        e.g.  NULL (translates to) NotFound
//        e.g.  AddError(&lt;string&gt;) can only be interpreted as "other" errors since they are just descriptions of the error and not the type
public IValidator&lt;Thing&gt; RemoveThing(int id)
{    
    var thing = _repository.Get(id);
    // NOTE: this result has to be interpreted by the caller
    if (thing == null)
        return null; 

    var validator = new ThingValidator(thing);
    var isValid = validator.Validate(new StatusSpecification("UnIndexed"));    

    if (isValid)
    {
        thing.Delete();  
        _repository.Save(thing);
    }
    else
    {
        // NOTE: since this message comes from outside of the class, it
        //         it not the nearest source of truth about what went wrong.
        //         i think this message should come from the class itself.
        //          this message is also typed twice in your code.
        validator.AddError("Only an UnIndexed thing may be deleted.");
    }

    return validator;
}

public JsonResult DeleteThing(int thingId)
{
    var command = _service.RemoveThing(thingId);

    // NOTE: this could be set up so that you don't have to interpret null as "not found"
    if (command == null)
        return Json(HttpStatusCode.NotFound);

    if (command.IsValid())
    {
        return Json(HttpStatusCode.OK);
    }
    else
    {
        return Json(command.ListErrors());
    }
}


OPTION #1


short and to the point.  
idiomatic solution 
very little logic. 
explicitly typed errors for try/catch handling


THROW ALL THE EXCEPTIONS!!!

public void Delete()
{
    if (Status == "UnIndexed")
        Deleted = true;
    else
        throw new UnIndexedException();
}

public void RemoveThing(int id)
{    
    var thing = _repository.Get(id);
    if (thing == null)
        throw new ThingNotFoundException(id); 

    thing.Delete();  
    _repository.Save(thing);    
}

// Controller
public JsonResult DeleteThing(int thingId)
{
    try
    {
        _service.RemoveThing(thingId);
        return Json(HttpStatusCode.OK);
    }
    catch (ThingNotFoundException e)
    {
        return Json(HttpStatusCode.NotFound);
    }    
    catch (Exception e)
    {
        throw;
    }
}


OPTION #2 


less short but still to the point.  
inching towards a more declarative solution. (which is good)
not that much logic. 
explicitly stated errors for if/then handling


NEVER THROW EXCEPTIONS!!!

class RemoveThingResult
{
    private RemoveThingResult(bool isOk, boo isNotFound, bool isUnIndexed)
    {
        IsOk = isOk; IsNotFound = isNotFound; IsUnIndexed = isUnIndexed;
    }

    public readonly bool IsOk;
    public readonly bool IsNotFound;
    public readonly bool IsUnIndexed;

    public static RemoveThingResult Ok()
    {
        return new RemoveThingResult(true, false, false);
    }
    public static RemoveThingResult NotFound()
    {
        return new RemoveThingResult(false, true, false);
    }
    public static RemoveThingResult UnIndexed()
    {
        return new RemoveThingResult(false, false, true);
    }
}

// Service Layer
public RemoveThingResult RemoveThing(int id)
{    
    var thing = _repository.Get(id);    

    if (thing == null)
        return RemoveThingResult.NoFound(); 

    var validator = new ThingValidator(thing);
    if (!validator.Validate(new StatusSpecification("UnIndexed")))
        return RemoveThingResult.UnIndexed(); 

    thing.Delete();  
    _repository.Save(thing);

    return RemoveThingResult.Ok(); 
}

// Controller
public JsonResult DeleteThing(int thingId)
{
    var command = _service.RemoveThing(thingId);

    if (command.IsNotFound)
        return Json(HttpStatusCode.NotFound);

    if (command.IsOk)    
        return Json(HttpStatusCode.OK);

    if (command.IsUnIndexed)    
        return Json("Only an UnIndexed thing may be deleted.");

}