Inserting a chart in a template throws exception "Message='rId10' ID conflicts with the ID of an existing relationship for the specified source."

Nov 26, 2013 at 6:12 PM
Edited Nov 26, 2013 at 6:14 PM
Dear all,

I am wondering if anyone has had a similar uses case to tackle.

I am populating a template with some data based on values on database. The tag delimiter I use in the template is {varName}. Docx is doing a remarkable job with making that happen.

What I am having difficulty with is figuring out how I can insert a chart at a predetermined area inside the template template. I tried to create a chart and just call the InsertChart(…) on the docx object:
1) The exception bellow occurs when the template.InsertChart(…) is called

2) If No-1 can be fixed how can I programmatically tell docx where to place the created chart? I did not see a way how to specify a tag or location

3) If No-1 or No-2 are a no go does anyone have any suggestions how I could accomplish this?

Here are some pieces of my code:
DocX template = DocX.Load("c:\\temp\\StateProfileTemplate.docx");
template.ReplaceText("{var1}", "38,300");
template.ReplaceText("{var2}", "Alabama");
template.ReplaceText("{var3}", "6th");
template.ReplaceText("{varText1}", varText1);
template.ReplaceText("{varText2}", varText2);
template.ReplaceText("{varText3}", varText3);
template.ReplaceText("{varText4}", varText4);
PieChart c = createMyChart();
template.InsertChart(c);
template.SaveAs("c:\\temp\\alabama.docx");
Here is the exception:
System.Xml.XmlException was unhandled
  HResult=-2146232000
  Message='rId10' ID conflicts with the ID of an existing relationship for the specified source.
  Source=WindowsBase
  LineNumber=0
  LinePosition=0
  StackTrace:
       at MS.Internal.IO.Packaging.InternalRelationshipCollection.ValidateUniqueRelationshipId(String id)
       at MS.Internal.IO.Packaging.InternalRelationshipCollection.Add(Uri targetUri, TargetMode targetMode, String relationshipType, String id, Boolean parsing)
       at System.IO.Packaging.PackagePart.CreateRelationship(Uri targetUri, TargetMode targetMode, String relationshipType, String id)
       at Novacode.DocX.InsertChart(Chart chart)
       at StateProfilesCon.Program.createChart(DocX template) in c:\MyProjects\Microsoft\StateProfilesCon\StateProfilesCon\Program.cs:line 159
       at StateProfilesCon.Program.Template() in c:\MyProjects\Microsoft\StateProfilesCon\StateProfilesCon\Program.cs:line 134
       at StateProfilesCon.Program.Main(String[] args) in c:\MyProjects\Microsoft\StateProfilesCon\StateProfilesCon\Program.cs:line 21
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
I tried looking for a similar question on the forum but could not find it.

Thanks in advance for any help

max
Developer
Nov 26, 2013 at 6:14 PM
are you using source code version or the binary?
Nov 26, 2013 at 6:17 PM
Hi Madboy

I am using the latest binary from the download link of the homepage. is that the issue?

thanks
max
Developer
Nov 26, 2013 at 6:19 PM
It could be. Go to source codes and compile new version from there. There's a lot of fixes in that version.
Nov 26, 2013 at 6:20 PM
Thanks will give that a try and will let you know either way how it goes

max
Nov 26, 2013 at 7:46 PM
Hi MadBoy,


I took the source down and rebuilt the DLL but unfortunately I am having the same issue. When GetNextFreeRelationshipID{} is called it generates rId10. Then it calls the mainPart.CreateRelationship(…) and passes it the relId then the exception occurs.

While debugging I changed the relID generated to rId101 and the chart was successfully inserted in the document.

It’s peculiar that no one has the same issue now I am wondering if I am doing something wrong.

Thanks,

max
Developer
Nov 26, 2013 at 7:49 PM
Most likely a bug and since probably very few people use charts it's not used much. Feel free to dive into sourcecode and fix it and propose a patch. Most likely rld10 id already exists so, a new one should be generated prior insert.
Nov 27, 2013 at 8:17 PM
Edited Nov 28, 2013 at 11:21 PM
Hi MadBoy

Finally got around looking into the issue and you were right on point. GetNextFreeRelationshipID{} has the issue and in particular the following code:
    int id =
    (
         from r in mainPart.GetRelationships()
         select r.Id
    ).Max();
As I stepped through the code I noticed that it would have rId1, .... rId9, rId10 but the max value would always be rId9. The single digit IDs are not padded with "0" (i.e. rId01, rId09) unlike the comment in the code but I am not sure why. This is what I modified in the method:

1) Changed the id to int
2) On the linq expression modified the select to int.Parse(r.Id.Substring(3))
3) Added a where clause looking for rId where r.Id.Substring(0, 3).Equals("rId")
4) Removed the line of code that removes the rId text - string newId = id.Replace("rId", "");
5) Converted the int back to string
6) Everything else remains the same
       private string GetNextFreeRelationshipID()
        {
           int id =  (  
                from r in mainPart.GetRelationships()
                where r.Id.Substring(0, 3).Equals("rId")
                select int.Parse(r.Id.Substring(3))  
            ).DefaultIfEmpty().Max();

           // The conventiom for ids is rid01, rid02, etc
           string newId = id.ToString();  
            int result;
            if (int.TryParse(newId, out result))
                return ("rId" + (result + 1));
            else
            {
                String guid = String.Empty;
                do
                {
                    guid = Guid.NewGuid().ToString();
                } while (Char.IsDigit(guid[0]));
                return guid;
            }
        }
Let me know what you think. I am little concerned that the proposed changes may affect something else.

Thanks

max
Marked as answer by MadBoy on 12/22/2013 at 5:55 AM
Developer
Dec 22, 2013 at 12:54 PM
Hello Max,

I've commited your change. IF you can test it out and let me know that would be great. I tested it on examples and it works fine on Office 2010. I do know that charts seems to be broken on Word 2013 (not sure why thou).

With regards,
Przemek