1

when i am creating salesforce custom object in C# using salesforce metadata api i am getting following error:

FIELD_INTEGRITY_EXCEPTION Must specify a nameField of type Text or AutoNumber CODE:

        CustomObject cObject = new CustomObject();
        cObject.fullName = "Vistaa__c";
        cObject.deploymentStatus = metaforce.DeploymentStatus.Deployed;
        cObject.deploymentStatusSpecified = true;
        cObject.description = "Created by metadata API";

        cObject.enableActivities = true;
        cObject.enableActivitiesSpecified = true;
        cObject.label = "Vista Object";
        cObject.pluralLabel = cObject.label + "s";
        cObject.sharingModel = metaforce.SharingModel.ReadWrite;
        cObject.sharingModelSpecified = true;
        CustomField cf = new CustomField();
        cf.description = "Simple text field from API";
        cf.fullName = "Lead." + cObject.fullName + "__c";
        String fieldLabel = "";
        cf.label = fieldLabel.Length == 0 ? "Sample Field" : "Sample Field";
        cf.length = 50;
        cf.type = FieldType.Text;
        cObject.nameField = cf;

        SaveResult[] results = ms.createMetadata(new metaforce.Metadata[] { cObject });

2 Answers 2

3

TL;DR:

cf.typeSpecified = true;

Clarifying the question:

The other answer mistakenly assumes there is an existing Custom Object and we are getting an error when creating new records for it.

The question is actually regarding use of the Salesforce Metadata SOAP API from C# to create a Custom Object that did not previously exist. It has nothing to do with creating new records in an existing Custom Object.

The pain persists:

It's nearly two years later, and I hit the same problem. Nothing I found gave a working answer, but I found three places online (including this SE question) where someone was asking how to solve this problem, and did not get a working answer. (I attempted to include the links here, but SE didn't like it, so you'll have to take my word for it. :) )

Why this solves the problem:

Microsoft Visual Studio (even 2015, which I'm using) has a "feature" (extremely poor design IMHO) where, when generating .NET code from a WSDL file for a SOAP web service, optional properties are botched in a workable but not-nice way.

You would expect that setting a value to the optional property would be all you need to do.

But actually, you need to set a value to the optional property, and also set the corresponding ...Specified property to "true".

On the CustomField object, the "type" property is optional. Due to this bug/quirk/design-flaw/"feature" in .NET's default handling of WSDL, setting the CustomField.type without also setting typeSpecified = true, has the same effect as not setting the type at all.

To get more technical, the problem occurs at the point of serialization to XML. The XML serializer will not output to XML, any optional property where the corresponding ...Specified property == false.

A C# code sample that actually works:

var sec = new SalesforceEnterpriseApi.SoapClient(); // Salesforce Enterprise Client
var loginResponse = sec.login(null, "[email protected]", "your.password.and.security.token");
var metadataSession = new SalesforceMetadataApi.SessionHeader();
metadataSession.sessionId = loginResponse.sessionId;
var smc = new SalesforceMetadataApi.MetadataPortTypeClient(); // Salesforce Metadata Client
smc.Endpoint.Address = new System.ServiceModel.EndpointAddress(loginResponse.metadataServerUrl);

var co = new CustomObject();
co.deploymentStatus = DeploymentStatus.InDevelopment;
co.deploymentStatusSpecified = true;
co.fullName = "AwesomeCustomObject__c";
co.label = "Awesome Custom Object";
co.pluralLabel = "Awesome Custom Objects";
co.sharingModel = SharingModel.ReadWrite;
co.sharingModelSpecified = true;

var cf = new CustomField();
cf.type = FieldType.Text;
cf.typeSpecified = true;
cf.label = "Name Field";
co.nameField = cf;

var upsertResponse = smc.upsertMetadata(metadataSession, null, null, new Metadata[] { co });
var readResponse = smc.readMetadata(metadataSession, null, "CustomObject", new string[] { "AwesomeCustomObject__c" });

Prerequisites:

  1. Download WSDL and generate service wrappers for Enterprise WSDL and Metadata WSDL. (Log into Salesforce, click "Setup" towards top right, then in search box at top of left sidebar menu, type "api" but do NOT press Enter. The left sidebar menu should shrink down to just one item called "API". Click into that, and then it's easy to download the two WSDL files I mentioned.)
  2. Put the sample code in a function/method, and in the same code file, import both the Enterprise API and Metadata API namespaces with appropriate "using" lines.
  3. Put your Salesforce username in place of "[email protected]".
  4. Obtain your Salesforce security token (log into SF, click your username in top bar and click "My Settings" from the resulting popup menu, then in left sidebar navigation, click "Personal", and from the submenu that expands, click "Reset My Security Token" and follow the instructions there).
  5. Append your Salesforce security token to your password (with nothing between them) and put that in place of "your.password.and.security.token".

I don't think I'm exaggerating to say that this simple actually working C# sample code for creating new Custom Objects through the Metadata API, including the simple, correct, instructions for connecting to the API in the first place, would've saved me a few days of effort. I hope it helps someone else!

1
  • Thank you very much for this. It's saved me hours of pain... really annoying way to handle WSDL's, .Net! I have taken the liberty of editing your post as the TL;DR contained a typo.
    – mkorman
    Oct 25, 2017 at 10:54
1

Every object that you create in Salesforce has some standard fields. One of them is called Name. This can be in the format of Text or an auto-number and you must specify a value because it is mandatory. You can see this by going into Setup -> Create -> Objects -> Your Custom Object and under the Standard Fields section you would see the field Name and click edit next to it. enter image description here

If it's selected as text then you can enter any value, if it's specified as auto-number you must populate according to the format. As you can see in the picture it can be A-{0000}, where A is the code of the custom object and the sequence of numbers are how big the auto number can be enter image description here

So in your code you should do something like this:

cObject.Name = "TestName";

Hope it helps

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .