writing project custom fields using PSI - no data being written?

  • Thread starter Stephan Steiner
  • Start date
S

Stephan Steiner

Hi

I forgot to check until today when I wanted to update one of my test
projects and see if setting a field to the same value as it already had
would still return something to be updated when I call
ProjectDataSet.GetChanges(DataRowState.Modified) - and then to my surprise
it turns out those CFs weren't even there.

Basically, when I create a project, I also add 29 entries to the
ProjectDataSet.ProjectCustomFieldsDataSet - then I call
ProjectWebSvc.CreateProject(ProjectDataSet). That works just fine, the
project is being written and can be opened in the client afterwards, but all
CFs I set are gone.

When I open an existing project that has those CFs, I have no trouble
dumping them. Also, I've started writing tasks with CFs and those CFs stick.

So I figured perhaps I cannot write Project CFs upon project creation so I
checked out the project after creation, wrote the Project CFs, then
submitted them

(by first calling ProjectDataSet.GetChanges(DataRowState.Added) and calling
QueueAddToProject on that dataset, then by calling
ProjectDataSet.GetChanges(DataRowState.Modified) and calling
QueueUpdateProject (the latter because my code automatically takes care of
updating a CF if it should already exist.. and since some of my CFs have
default values, they exist but don't necessarily have the value I want them
to have).

And this is what happens:

QueueAddToProject fails with an CustomFieldRequiredValueNotProvided error.
QueueUpdateProject runs without a glitch

I turn the SoapException into PSILibrary.PSClientError and go through it -
but it isn't very helpful. ErrorAttributeNames() returns mdpropuid and the
matching entry in ErrorrAttributes is an empty string. So here's a
sidequestion.. where's the useful information? I finally managed to get some
more useful error info by accessing the private properties of
PSIClientError - errorInfoXml finally provided some useful information:

<errinfo><dataset name=\"ProjectDataSet\"><table
name=\"ProjectCustomFields\"><row
CUSTOM_FIELD_UID=\"79298157-67fb-4a64-b933-77e4890a030c\"><error
id=\"11713\" name=\"CustomFieldRequiredValueNotProvided\"
uid=\"6d62326f-75c5-4c0e-93ff-44cb855e0140\" mdpropuid=\"\"
/></row></table></dataset></errinfo>

Stil.. the main problem here is that I have a CUSTOM_FIELD_UID.. but those
values are all newly created GUIDs.. useful information would be the
MD_PROP_ID or MD_PROP_UID so you know which CF lacks the value. And is
finding the error really supposed to be trial and error until you find the
appropriate field and using reflection to access private variables to get
some useful bit of info?

So in the end I'm stuck with 3 questions:

1) How do you write Project CFs upon project creation?
2) Am I doing something fundamentally wrong in writing the project CFs
(using the same approach as writing Task CFs.. the latter ones work just
fine)
3) Is there no way to extract useful information from an error (even
accessing the private variable you still need to propagate it back and
search the data set for the appropriate entry then re-match against the
CustomField definition to know which field caused the problem).

Regards
Stephan
 
S

Stephan Steiner

Stephen

I haven't properly debugged yet so I don't know yet what is empty - however, the error I get from the internal variable says something else entirely.. and I can be sure that all MD_PROP_UID fields are not empty (the way I fill out the CFs make it impossible - I look up the CustomFieldsRow first, then create the ProjectCustomFieldsRow based on the CustomFieldsRow and since MD_PROP_UID is a mandatory parameter and it is always copied there won't be any empty UIDs) - I also do not call AcceptChanges anywhere.

Regards
Stephan
"Stephen Sanderlin" <stephen NS-DOT sanderlin A-NS-T msprojectexperts DOT-NS com> wrote in message From the error, it looks like MD_PROP_UID is blank? You're not calling AcceptChanges() anywhere, are you? If so, review this blog post: http://blogs.msdn.com/brismith/arch...ect-server-datasets-and-the-web-services.aspx.


--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com
 
S

Stephan Steiner

Stephen

After making some progress in other areas I managed to debug the problem. I had my code dump all guids when creating/writing CFs and based on that and the internal error xml text I was able to identify which field was the problem - turns out it was effectively my problem as I had written code taking an object, and then having to cast the input and put it into the appropriate *_VALUE and I forgot one field which comes in as a long.

However, that still leaves the question about the useles error message and why the full error is not being returned to me without reflection - am I mistaken assuming I should get the full error message?

Regards
Stephan
"Stephen Sanderlin" <stephen NS-DOT sanderlin A-NS-T msprojectexperts DOT-NS com> wrote in message From the error, it looks like MD_PROP_UID is blank? You're not calling AcceptChanges() anywhere, are you? If so, review this blog post: http://blogs.msdn.com/brismith/arch...ect-server-datasets-and-the-web-services.aspx.


--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com
 
S

Stephen Sanderlin

I've found that I get more complete error messages by including the
error in exception.Detail.InnerXML. I'm sure there's other information
around in the object as well.



Have you examined the code in the SDK that demonstrates extracting
information out of a PsiErrorInfo[] object? If not, you should. You can
find it included in most of the SDK articles that contain sample code.

--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com





<
Stephen



After making some progress in other areas I managed to debug the
problem. I had my code dump all guids when creating/writing CFs and
based on that and the internal error xml text I was able to identify
which field was the problem - turns out it was effectively my problem as
I had written code taking an object, and then having to cast the input
and put it into the appropriate *_VALUE and I forgot one field which
comes in as a long.



However, that still leaves the question about the useles error message
and why the full error is not being returned to me without reflection -
am I mistaken assuming I should get the full error message?



Regards

Stephan

"Stephen Sanderlin" <stephen NS-DOT sanderlin A-NS-T msprojectexperts
DOT-NS com> wrote in message

From the error, it looks like MD_PROP_UID is blank? Youre not calling
AcceptChanges() anywhere, are you? If so, review this blog post:
http://blogs.msdn.com/brismith/arch...ect-server-datasets-and-the-web-services.aspx.


--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com
 
S

Stephan Steiner

Stephen

I actually copied the error handling code from one of the SDK samples. My full error processing code is as follows:

private void processSoapException(System.Web.Services.Protocols.SoapException ex, string methodcall)
{
string errMess = "Soap exception during call to " + methodcall;
PSLibrary.PSClientError error = new PSLibrary.PSClientError(ex);
PSLibrary.PSErrorInfo[] errors = error.GetAllErrors();

foreach (PSLibrary.PSErrorInfo err in errors)
{
string[] attributeNames = err.ErrorAttributeNames();
errMess += "".PadRight(30, '=') + "\r\nPSCLientError Output:\r\n \r\n";
errMess += err.ErrId.ToString() + ", name " + err.ErrName + "\n";
for (int j = 0; j < err.ErrorAttributes.Length; j++)
{
errMess += "\r\n\t" + err.ErrorAttributeNames()[j] + ": " + err.ErrorAttributes[j];
}
errMess += "\r\n".PadRight(30, '=');
}
errMess = errMess + "\n" + ex.Message.ToString();
Console.WriteLine(errMess);
}

But since InnerXML is a private variable, it doesn't get dumped.

Is there a different way to handle this?

Regards
Stephan
"Stephen Sanderlin" <stephen NS-DOT sanderlin A-NS-T msprojectexperts DOT-NS com> wrote in message I've found that I get more complete error messages by including the error in exception.Detail.InnerXML. I'm sure there's other information around in the object as well.



Have you examined the code in the SDK that demonstrates extracting information out of a PsiErrorInfo[] object? If not, you should. You can find it included in most of the SDK articles that contain sample code.

--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com






Stephen



After making some progress in other areas I managed to debug the problem. I had my code dump all guids when creating/writing CFs and based on that and the internal error xml text I was able to identify which field was the problem - turns out it was effectively my problem as I had written code taking an object, and then having to cast the input and put it into the appropriate *_VALUE and I forgot one field which comes in as a long.



However, that still leaves the question about the useles error message and why the full error is not being returned to me without reflection - am I mistaken assuming I should get the full error message?



Regards

Stephan

"Stephen Sanderlin" <stephen NS-DOT sanderlin A-NS-T msprojectexperts DOT-NS com> wrote in message
From the error, it looks like MD_PROP_UID is blank? Youre not calling AcceptChanges() anywhere, are you? If so, review this blog post: http://blogs.msdn.com/brismith/arch...ect-server-datasets-and-the-web-services.aspx.


--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com
 
S

Stephen Sanderlin

Stephan,



Here's the code I use and it works. I use this code to generate an
InvalidOperationException that wraps the original exception.



static internal class PsiError

{

static public InvalidOperationException
ExpandException(SoapException exception)

{

// Declarations

StringBuilder _errorMessage = new StringBuilder();

PSLib.PSClientError _psiError = new
PSLib.PSClientError(exception);

PSLib.PSErrorInfo[] _psiErrors = _psiError.GetAllErrors();




_errorMessage.Append("==============================\r\nError: \r\n");



// Loop through and extract all errors

for (int _errorCount = 0; _errorCount < _psiErrors.Length;
_errorCount++)

{

_errorMessage.Append("\n" + exception.Message.ToString()
+ "\r\n");

_errorMessage.Append("".PadRight(30, '=') +
"\r\nPSClientError Output:\r\n \r\n");


_errorMessage.Append(_psiErrors[_errorCount].ErrId.ToString());



for (int _errorAttribCount = 0; _errorAttribCount <
_psiErrors[_errorCount].ErrorAttributes.Length; _errorAttribCount++)

{

_errorMessage.Append("\r\n\t" +
_psiErrors[_errorCount].ErrorAttributeNames()[_errorAttribCount]);

_errorMessage.Append(": " +
_psiErrors[_errorCount].ErrorAttributes[_errorAttribCount]);

}

_errorMessage.Append("\r\n".PadRight(30, '='));

}



_errorMessage.Append("\r\nException InnerXML:\r\n \r\n");

_errorMessage.Append(exception.Detail.InnerXml);

_errorMessage.Append("\r\n".PadRight(30, '='));



return new
InvalidOperationException(_errorMessage.ToString(), exception);

}

}



Hope this helps!

Steve


--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com





<
Stephen



I actually copied the error handling code from one of the SDK samples.
My full error processing code is as follows:



private void
processSoapException(System.Web.Services.Protocols.SoapException ex,
string methodcall)
{
string errMess = "Soap exception during call to " +
methodcall;
PSLibrary.PSClientError error = new
PSLibrary.PSClientError(ex);
PSLibrary.PSErrorInfo[] errors = error.GetAllErrors();



foreach (PSLibrary.PSErrorInfo err in errors)
{
string[] attributeNames = err.ErrorAttributeNames();
errMess += "".PadRight(30, '=') + "\r\nPSCLientError
Output:\r\n \r\n";
errMess += err.ErrId.ToString() + ", name " +
err.ErrName + "\n";
for (int j = 0; j < err.ErrorAttributes.Length; j++)
{
errMess += "\r\n\t" + err.ErrorAttributeNames()[j] +
": " + err.ErrorAttributes[j];
}
errMess += "\r\n".PadRight(30, '=');
}
errMess = errMess + "\n" + ex.Message.ToString();
Console.WriteLine(errMess);
}



But since InnerXML is a private variable, it doesn't get dumped.



Is there a different way to handle this?



Regards

Stephan

"Stephen Sanderlin" <stephen NS-DOT sanderlin A-NS-T msprojectexperts
DOT-NS com> wrote in message

Ive found that I get more complete error messages by including the
error in exception.Detail.InnerXML. Im sure theres other information
around in the object as well.



Have you examined the code in the SDK that demonstrates extracting
information out of a PsiErrorInfo[] object? If not, you should. You can
find it included in most of the SDK articles that contain sample code.

--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com





<
Stephen



After making some progress in other areas I managed to debug the
problem. I had my code dump all guids when creating/writing CFs and
based on that and the internal error xml text I was able to identify
which field was the problem - turns out it was effectively my problem as
I had written code taking an object, and then having to cast the input
and put it into the appropriate *_VALUE and I forgot one field which
comes in as a long.



However, that still leaves the question about the useles error message
and why the full error is not being returned to me without reflection -
am I mistaken assuming I should get the full error message?



Regards

Stephan

"Stephen Sanderlin" <stephen NS-DOT sanderlin A-NS-T msprojectexperts
DOT-NS com> wrote in message

From the error, it looks like MD_PROP_UID is blank? Youre not calling
AcceptChanges() anywhere, are you? If so, review this blog post:
http://blogs.msdn.com/brismith/arch...ect-server-datasets-and-the-web-services.aspx.


--

Stephen Sanderlin

Principal Consultant

MSProjectExperts



For Project Server Consulting: http://www.msprojectexperts.com

For Project Server Training: http://www.projectservertraining.com



Read my blog at: http://www.projectserverhelp.com/

Join the community at: http://forums.epmfaq.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top