0

I'm building an VS C# 5-Tier solution with UI, Service, Logic, Business-Data and Data-Layers projects. I'm using WCF and EF6, with EF6 loaded into the UI, the Service and the Data layers. I'm using ADO.NET for Entities in the Data Layer, and my Entity was built as Database-first.

I have a DataGridView control on my UI Win-Form and I want to view all or select members of my organization in the DataGridView on demand.

When I instantiate my Service in the UI, my code works to get the requested data rows to return from the data layer (EF query), back through logic layer, to Service layer.

But when I try to use the Service layer's returned object, I receive the "Object reference not set to an instance of an object" error.

My goal is to use the returned list as the data source for a Binding Source control for my DataGridView. I also need help in understanding how to get the I-List object to expose to its object level. Any help would be appreciated, thanks.

** Service Contract: **
***
 [DataContract]
 public class MemberList
 {
    [DataMember]
    public IList MembersInList { get; set; }
 }
***
[DataContract]
public class Member
{
    [DataMember]
    public int MemberID { get; set; }
    [DataMember ]
    public string Last_Name { get; set; }
    [DataMember]
    public string First_Name { get; set; }
    [DataMember]
    public string MidInit { get; set; }
    [DataMember]
    public string Email_Address { get; set; }

}
***
 ** Here's my datalayer: **
***
    public MemberBDOList FillMemberGrid()
    {
        MemberBDOList myDAO = new MemberBDOList();

        using (var afDBEntities = new AFDBEntities())
        {
            var members = afDBEntities.Members.ToList();    // gets all 68 Members in MSSQL table 

            if (members != null)
            {
                myDAO.MembersBDOInList = members; 
            }
        }
        return myDAO as MemberBDOList;  //returns all 68 Members to Logic Layer as collection
    }

***
** Here's my Service.cs object (Service layer): **
***
    public MemberList FillMemberGrid()
    {
        MemberBDOList  objMembersBDO = null;
        try
        {
            objMembersBDO = new MemberBDOList();
            objMembersBDO = memberLogic.FillMemberGrid();
        }
        catch (Exception e)
        {
            var msg = e.Message;
            var reason = "FillMemberGrid Exception";
            throw new FaultException<MemberFault>(new MemberFault(msg), reason);
        }

        if (objMembersBDO.MembersBDOInList == null)
        {
            var msg = string.Format("No members were found.");
            var reason = "FillMemberGrid: Empty Entity Member";
            throw new FaultException<MemberFault>(new MemberFault(msg), reason);
        }

        var objMembers = new MemberList();

        TranslateMembersBDOToMembersDTO(objMembersBDO, objMembers);  // method below
        return objMembers.MembersInList  as MemberList;
    }
    private void TranslateMembersBDOToMembersDTO(MemberBDOList objMembersBDO, MemberList objMembers)
    {
        objMembers.MembersInList = objMembersBDO.MembersBDOInList;
    }
 }
***
** Here is the Business-Data object: **
***
[Serializable]
  public class MemberBDOList
  {
        public IList MembersBDOInList { get; set; }
  }

***

** And here are the UI methods: **
***

    MemberServiceProxy.Member member;
    MemberServiceProxy.MemberList memberList;   

    private void btnFillMemberGrid_Click(object sender, EventArgs e)
    {
        BindingSource bSrc = new BindingSource();

        int M = 0;
        try
        {
            M = 1;
            memberList = GetMemberList();

            M = 3;
            //fails here with "Object reference not set to an instance of an object."
            bSrc.DataSource = memberList.MembersInList.ToList();  // fails with or without To-List

            M = 5;
            adgView.DataSource = bSrc;

            M = 7;
            adgView.Refresh();

        }
        catch (Exception ex)
        {
        }
    }

    private MemberList GetMemberList()
    {
        var results = new MemberList();
        int M = 0;
        try
        {
            M = 1;
            var client = new MemberServiceClient();

            M = 3;
            //go get the member list from Data Layer EF
            results = client.FillMemberGrid();

            return results;
        }
        catch (Exception ex)
        {
            return results;
        }
    }

 ***

** Code update in Data Layer and in Service Layer - to translate the DataContract "Members" object at the data member level in List. Showing DAL layer here. **

 ***
    public MembersBDO FillMemberGrid()
    {
        var membersBDO = new MembersBDO();
        var memberBDO = new MemberBDO();

        int M = 0;
        try
        {
            M = 1;
            using (var afDBEntities = new ACTSFactsDBEntities())
            {
                M = 3;
                var members = afDBEntities.Members.ToList();    // gets all 68 Members in MSSQL table (Entity is Database-first)

                M = 5;
                //     if (members != null)
                //     {
                //         M = 7;
                //         membersBDO.MemberBDOList = members;  //this works with the IList data contract, 
                //                                      //but the IList data, unconverted, belongs to the data layer -  no conversion is done
                //                                      //here from DAL data types to BDO data types at the members[index].(columnName) level
                //     }

                //so, (below) this solves that issue, and converts to the [DataMember] level (the data row's columns)
                //for each [DataContract] Member in "members" - the List<Member> object which belongs to the data layer project.
                //                                              
                M = 9;
                if (members != null)            //the data layer object has rows, good.
                {
                    int n = 0;
                    foreach (Member m in members)       //read through each data layer  EF Member type in "members" list
                    {
                        memberBDO = new MemberBDO()   //instantiate a new MemberBDO type to translate the DAL member.Columns to
                        {
                            MemberID = m.MemberID,        //each DAL column must be translated to its matching BDO type
                            Last_Name = m.Last_Name,
                            First_Name = m.First_Name,
                            MidInit = m.MidInit,
                            Email_Address = m.Email_Address,
                            Home_Phone = m.Home_Phone,
                            Cell_Phone = m.Cell_Phone,
                            Mailing_Address = m.Mailing_Address,  etc
                         };

                         membersBDO.memberBDOList.Add(memberBDO); 
                         memberBDO = null;
                        n += 1;
                        if (n > 60) break; // my code breaks at request for all 68 rows with error 
                                                 // - "MaxReceivedMessageSize" (65536 bytes) property exceeded
                    }
                }
                M = 11;
                return membersBDO;    //returning 61 of my 68 Members works to Service layer, through Logic Layer
 }                                                              
        }
 ***

** Changes to code in Service layer: **

 ***
    public Members FillMemberGrid()
    {
        MembersBDO objMembersBDO = null;
        try
        {
            objMembersBDO = new MembersBDO();
            objMembersBDO = memberLogic.FillMemberGrid();
        }
        catch (Exception e)
        {
            var msg = e.Message;
            var reason = "FillMemberGrid Exception";
            throw new FaultException<MemberFault>(new MemberFault(msg), reason);
        }

        if (objMembersBDO == null)
        {
            var msg = string.Format("No members were found.");
            var reason = "FillMemberGrid: Empty Entity Member";
            throw new FaultException<MemberFault>(new MemberFault(msg), reason);
        }

        var objMembers = new Members();

        TranslateMembersBDOToMembersDTO(objMembersBDO, objMembers);  //a private method defined below

        return objMembers as Members;
    }
    private void TranslateMembersBDOToMembersDTO(MembersBDO objMembersBDO, Members objMembers)
    {
        //objMembers.MemberList = objMembersBDO.MemberBDOList;
        foreach (MemberBDO mBDO in objMembersBDO.memberBDOList)
        {
            Member m = new Member();
            TranslateMemberBDOToMemberDTO(mBDO, m);  //calling the same translate code that translates the return of a one member request 
            objMembers.MemberList.Add(m);
            m = null;
            m = new Member();
        }
    }
 ***

** Changes to [DataContract] Members class in IMemberService.cs **

 ***
  [DataContract]
  public class Members
  {
    [DataMember]
    public List<Member> MemberList { get; set; }  = new List<Member>();   
  }

 ***

** Here's the change to class MembersBDO in the Business Domain Object layer **

 ***

 [Serializable]
 public class MembersBDO
 {
    public List<MemberBDO> memberBDOList { get; set; } = new List<MemberBDO>();
 }

 ***
Cwinds
  • 167
  • 11
  • Paragraphs, are a thing... – TheGeneral May 09 '20 at 00:55
  • Also i have never seen an error message that says "*Object Reference not instantiated error*" did you just make this up? and lastly, have you put break points at various points in your code to see where things are happening, what's working, where the error gets thrown, what may be null ect? – TheGeneral May 09 '20 at 00:57
  • "Object reference not set to an instance of an object" - sorry bout that.. And I'll try to read up on the Paragraph thing soon. And yes, I have set breakpoints, but maybe they were not fine or filtered enough? I do see my data coming back as an IList from EF data layer - using break points in debugging. – Cwinds May 09 '20 at 01:06

2 Answers2

1

Your return statement in FillMemberGrid() is returning null because you are trying to convert an IList to MemberList which won't work.

var objMembers = new MemberList();
TranslateMembersBDOToMembersDTO(objMembersBDO, objMembers);  // method below
return objMembers.MembersInList  as MemberList;

objMembers is already a member List. Why are you returning its MembersInList as MemberList? You should just return objMembers.

mbd
  • 81
  • 1
  • 2
  • Okay, I changed my return object to be "objMembers", and now receive a different error (posted below). Before the return object made it back, but with no Members in its list. ** The new error is: ** "An error occurred while receiving the HTTP response to http://localhost:8080/TheAFWCFService/MemberService/. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details." – Cwinds May 09 '20 at 21:42
  • I checked logs in wwwroot, found no errors relating to today's date for my application. Checked the app.config endpoint address in UI, and the connection strings in app.config's in DAL and Service layer, including web.config. – Cwinds May 09 '20 at 21:48
  • I changed my IServiceMember data contract to look like names used in the data layer's EF, ie 'Members' and 'Member', but it did not correct the error or change anything. **The affected Service contracts now looks like this:** *** [OperationContract] [FaultContract(typeof(MemberFault))] Members FillMemberGrid(); *** *** [DataContract] public class Members { [DataMember] public IList Member { get; set; } } *** – Cwinds May 09 '20 at 21:50
  • With these changes, the application still returns the list of DataLayer "Member" items all the way back to the MemberService.cs, but not into the UI. And the app still works when requesting or updating only one Member from EF/Database. Thanks for answering, 'mbd'. But, the issue now seems to be that the UI doesn't accept the resulting list - at least that's what I think the error is telling me, and I still can't get the Member list passed into the UI. – Cwinds May 09 '20 at 21:55
  • This seems to me to be the meaningful piece of the error msg: "This could also be due to an HTTP request context being aborted by the server" - because when I use the WCF Test Client between Service and Data Layer - the test Client "grays out" my "FillMemberGrid" method and won't let me use it - saying it's "not supported in the WCF Test Client because it uses type .Members. " ** Any ideas on how I can reconfigure my Data Contract? ** – Cwinds May 09 '20 at 22:15
  • My DB Context from EDMX is: public virtual DbSet Members { get; set; } – Cwinds May 09 '20 at 22:24
  • I think the `IList MembersInList` property could be the issue. See [this answer](https://stackoverflow.com/a/10647027/881253) for using a list. In that case change it to `List MembersInList` or just simply use `Member[] MembersInList`. – mbd May 10 '20 at 12:56
  • @mdb: thanks for the reply, I looked at link and tried a few things with no luck. I just tried to post an image of the data listed in my "objMembers" object. Using IList as the type in the Data Contract is the only way I can get anything to return from the DataLayer at this point. I'll keep at it. – Cwinds May 11 '20 at 05:38
  • The screenshot didn't work, but does `MembersBDOInList` list contain `Member` instances? Because if it doesn't , that's also an issue. Other than that I don't see, why it shouldn't work. If you have a minimal solution to reproduce the issue, I'd look at it. – mbd May 11 '20 at 15:14
  • thanks, you're right, I had to use List instead of IList in my DataContract. Plus, when I did that, VS suggested it be changed by adding " = new List();" after the {get; set;} on the property. So, I did that, then started working in my data layer to get all the data layer Member.Column (item level) converted to MemberBDO.Column level - before returning my MembersBDO object to the Service level. That's the main thing that I was missing, I think, that the Lists were not converted at the column "data member" level, only at a higher "Members" list level. Thanks, see code update. – Cwinds May 12 '20 at 21:56
  • One last comment, in the DataContract and the BDO class, adding the "new" instantiation to the List property allows me to ".Add()" a new Member to the Members object. Otherwise, I received "Object reference not set to an Instance of an object". Setting debug breakpoints really help to "see" what's going on, and if anyone wants to know where this n-Tier WCF Service , Entity Framework project took shape, you can check out this book: "WCF Multi-layer Services Development with Entity Framework" by Mike Liu. I own the well-used Fourth Edition. Thanks to all. – Cwinds May 12 '20 at 22:55
  • One more comment might be appropriate. I tried to update the pic of the returned object but couldn't get it to load. It showed the 68 Member data rows, but all prefixed with the datalayer name. Even though they were inside a Service.Member object. The "translating" at the [DataMember] (row/column) level put all of the encapsulated returned rows into the same type as the returning objects. This made even the smallest returned data item (Last_Name), for example, match the Service Contract, so the Service object now returns to the UI. At least that's what I think happened. – Cwinds May 12 '20 at 23:15
0

Thanks MBD, for your help in resolving my issue. We all need a sounding board, and your suggestion put me on the right track. See my updates for the answer that I finally came to use in the application. Still got issues, but not this one.

Cwinds
  • 167
  • 11
  • ** See this [link](https://stackoverflow.com/questions/884235/wcf-how-to-increase-message-size-quota) for the "MaxReceivedMessageSize" error resolution. ** – Cwinds May 13 '20 at 01:05