4

i follow this link Supporting OData Actions in ASP.NET Web API And i want to pass my object/Entity as a parameter like this:

ActionConfiguration addNewPatient = builder.Entity<Patient>().Collection.Action("AddNewPatient");
        addNewPatient.Parameter<int>("hospId");
        addNewPatient.Parameter<int>("docId");
        addNewPatient.Parameter<Patient>("patient");
        addNewPatient.Returns<bool>();

but i got this issue:

System.ArgumentException: Invalid parameter type 'Patient'. 
A non-binding parameter type must be either Primitive, Complex, Collection of Primitive or a Collection of Complex.
Parameter name: parameterType

I tried to implement this

   ActionConfiguration addNewPatient = builder.Entity<Patient>().Collection.Action("AddNewPatient");
    addNewPatient.Parameter<int>("hospId");
    addNewPatient.Parameter<int>("docId");
    var patientConfig = builder.StructuralTypes.OfType<EntityTypeConfiguration>().Single(x => x.Name == "Patient");
    addNewPatient.SetBindingParameter("patient", patientConfig, false);
    addNewPatient.Returns<bool>();

but i can't call method POST ../odata/Patient/AddNewPatient anymore

<FunctionImport Name="AddNewPatient" ReturnType="Edm.Boolean"      IsBindable="true">
<Parameter Name="patient" Type="Patient"/>
<Parameter Name="hospId" Type="Edm.Int32" Nullable="false"/>
<Parameter Name="docId" Type="Edm.Int32" Nullable="false"/>
</FunctionImport>

Please help me, i tried various way but still no luck. Thanks.

4
  • Somebody please help me :( Commented Nov 12, 2013 at 17:01
  • did you try builder.Entity<Patient>().Action("AddNewPatient") and the url odata/Patient('patient id')/AddNewPatient Commented Nov 14, 2013 at 5:45
  • According to the error message you must use a Complex type. •Complex type is a structured type without a key. If your patient has a key it won't work. Create a complex patient type in your model and use that as the parameter? Commented Apr 10, 2015 at 20:52
  • Any luck with this problem? I also want to send an entity to an action with several other parameters. Non-bindable of course Commented Jul 10, 2015 at 7:02

2 Answers 2

3

You can use the ActionConfiguration.EntityParameter() method to bind an entity as a parameter to your OData action method.

Here is an example:

ActionConfiguration validate = ModelBuilder.EntityType<TEntity>()
    .Collection.Action("Validate");
validate.Namespace = "Importation";
validate.EntityParameter<TEntity>(typeof(TEntity).Name);
validate.CollectionParameter<string>("UniqueFields");
validate.Returns<ValidationResult>();

However, note that the ModelState will not check against the content of the supplied Entity and will set any missing properties to null and properties exceeding the StringLength(x) annotation in your model will still pass. If you wish to validate the entity itself after, use this bit of code in your action method:

[HttpPost]
public virtual IHttpActionResult Validate(ODataActionParameters parameters)
{
//First we check if the parameters are correct for the entire action method
    if (!ModelState.IsValid)
    {
         return BadRequest(ModelState);
    }
    else
    {
         //Then we cast our entity parameter in our entity object and validate
         //it through the controller's Validate<TEntity> method
         TEntity Entity = (TEntity)parameters[typeof(TEntity).Name];
         Validate(Entity, typeof(TEntity).Name);
         if (!ModelState.IsValid)
         {
              return BadRequest(ModelState);
         }
         IEnumerable<string> uniqueFields = parameters["UniqueFields"] as IEnumerable<string>;
         bool result = Importer.Validate(Entity, uniqueFields);
         return Ok(result);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Note that you are not limited to using the entity type for the current controller, you are more likely to use this sort of entity post pattern when the entity that you are posting does not match the controller's type. You might be posting child entries against the parent object for instance.
0

Would it not be better to just POST to /odata/Patient your new patient object? that's kind of what it's there for.

If you want to do it the way you've described, you need to create an intermediate type, and make the parameter of that type, then convert between that and your Edm type.

var createPatient = modelBuilder.Entity<Patient>().Collection.Action("AddNewPatient");
createPatient.CollectionParameter<PatientPdo>("patient");

where PatientPdo is exactly the same as Patient, just with the navigation properties removed. That's what it's complaining about, that it's Edm types all the way down, so to speak.

public class PatientPdo
    {
        public long Id{ get; set; }

        public Entity ToEdmEntity()
        {
            return new Patient
                {
                    Id= Id
                };
        }
    }

2 Comments

Could you elaborate on how to "just POST the object"? I keep getting: A non-binding parameter type must be either Primitive, Complex, Collection of Primitive or a Collection of Complex.
-1 Because it is absolutely possible to pass the Entity typed object, must define the parameter as an EntityParameter<Patient>. We are using OData so that we can avoid creating custom data transfer objects for single use like this. You make a valid point that using the default POST action on this controller might be enough, however there are scenarios where you would like to implement custom alternate actions for posting data to your controller.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.