Search code examples
asp.netpostasp.net-web-apicontrollermany-to-many

HTTP POST to Many to Many relation using ASP.NET Web API


I am new to ASP.net (and programming in general) and I'm having trouble building a Web API. More specifically I need help in these two areas:

  1. How to configure my DOCcontroller to post a new document (DOC table).
  2. How to make the actual ajax post -- I am having trouble passing the EXT_GUID parameter. As it stands I get an error when I try to post. "Can't bind multiple parameters (doc and parentOwner) to the request's content."

Essentially this is for a simple document management system. I want Get/Post documents (DOC) by having the user supply an GUID from an external database (the EXT_GUID field) as a filter/parameter. Each document can have multiple EXT_GUIDs and each EXT_GUID can have multiple Documents (DOC). You can assume that the EXT_GUID fields we be populated prior to the http post.

This is the DOCcontroller code

//POST api/DOC
public HttpResponseMessage PostDOC(DOC doc, List<string> parentOwners)
{
    if (ModelState.IsValid)
    {            
        var parents = db.BIMs.Where(bx => parentOwners.Contains(bx.EXT_GUID));

        foreach (var p in parents)
        doc.Owners.Add(p);

        db.DOCs.Add(doc);
        db.SaveChanges();

        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, doc);
        response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = doc.Id }));
        return response;
    }
    else
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
}

This is my model setup -- EntityFramework codefirst stuff

public class EXT
{
    public int Id { get; set; }
    public string EXT_GUID { get; set; }
    public int ProjectID { get; set; }
    public virtual ICollection<DOC> DOCs { get; set; }
}

public class DOC
{
    public int Id { get; set; }
    public int ProjectID { get; set; }
    public string Subject { get; set; }
    public string Link { get; set; }
    public virtual ICollection<EXT> EXTs { get; set; }
}

This is more Storage Model...

public StoreDBContext() : base("name=StoreDBContext")
{
}
public DbSet<EXT> EXTs { get; set; }
public DbSet<DOC> DOCs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //Set FLUENT API config for many to many here
    modelBuilder.Entity<EXT>()
    .HasMany(a => a.DOCs)
    .WithMany()
    .Map(x =>
    {
        x.MapLeftKey("EXT_Id");
        x.MapRightKey("DOC_Id");
        x.ToTable("EXTsDOCs");
    });
}

AJAX Code

function AddDOC() {
    var parentOwner = "{\"" + $('#txtaddEXT').val() + "\"}";
    jQuery.support.cors = true;
    var DOC = {
        ProjectId: ProjectID,
        Subject: $('#txtaddDOCSubject').val(),
        Link: $('#txtaddDOCLink').val(),
            parentOwner: parentOwner
    };

    $.ajax({
        url: "http://localhost:54171/api/DOC/",
        type: 'POST',
        data: JSON.stringify(DOC),
        contentType: "application/json;charset=utf-8",
        success: function (data) {
            WriteResponse(data);
        },
        error: function (x, y, z) {
            alert(x + '\n' + y + '\n' + z);
        }
    });
}

Solution

  • What you receive from the client and what you will save in the database is two different things. Your doc object is ok:

    var DOC = {
        ProjectId: ProjectID,
        Subject: $('#txtaddDOCSubject').val(),
        Link: $('#txtaddDOCLink').val(),
        parentOwner: parentOwner
    };
    

    Now you need to change the server logic. Make a model like this:

    public class DocReceivedModel 
    {
        public int ProjectID { get; set; }
        public string Subject { get; set; }
        public string Link { get; set; }
        public List<string> parentOwner { get; set; }
    }
    

    Then your PostDOC method will be:

                public HttpResponseMessage PostDOC(DocReceivedModel docReceived)
                {
                    if (ModelState.IsValid)
                    {
                        Doc newDoc = new Doc();
                        newDoc.ProjectID = docReceived.ProjectID
                        newDoc.Subject = docReceived.Subject
                        newDoc.Link = docReceived.Link
    
                        var parents = db.BIMs.Where(bx => docReceived.parentOwners.Contains(bx.EXT_GUID));
                        foreach (var p in parents)
                            newDoc.Owners.Add(p);
                                // I not see in your model Owners, maybe this is EXTs but I suppose you catch the idea
    
                        db.DOCs.Add(newDoc);
                        db.SaveChanges();
    
                        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, newDoc);
                        response.Headers.Location = new Uri(Url.Link("DefaultApi", new {id = newDoc.Id}));
                        return response;
                    }
                    else
                    {
                        return Request.CreateResponse(HttpStatusCode.BadRequest);
                    }
                }