I am trying to use a Microsoft demo project which shows how to do ETW event tracing in WPF as a basis for some specific profiling I want to do in an app I'm developing.
Compiled as is, the demo works fine. However, change the target framework from .Net 3.5 to .Net 4, and it breaks. Clearly there is some significant change between the framework versions.
The question is what changed, and (more importantly) is it possible to fix the demo?
My investigation so far
Adding a Debug.WriteLine to FpsEventConsumer.EtwEventCallback I see that in framework 4 either no events arrive or two events arrive, both with Header.Guid of 68fdd900-4a3e-11d1-84f4-0000f80464e3; one with Header.Class.Type of UCE_GLASS_START and the other with UCE_GLYPHRUN_START. Note that I also observe these events, among many others, when testing under framework 3.5.
By digging around in referencesource.microsoft.com I discovered that MS.Utility.EventTrace's static field EventProvider of type MS.Utility.TraceProvider controls what gets sent to ETW. Using reflection to access the event provider (since it's non-public) I observe that in 3.5 it starts with everything enabled (_enabled is true, _flags is 2147483647, _level is 5); and in 4 it starts with everything disabled (_enabled is false, _keywords is 0, and _level is 0). But changing those values with reflection doesn't seem to help the situation much. At best, on a very rare occasion I get a few events emitted before the UCE_ ones mentioned above.
By placing a WriteLine in TraceConsumer.ProcessTrace as follows, I observe that the p/invoked call continues to block, so the problem isn't that the trace is being interrupted.
ErrorCode errorCode = UnsafeEventTrace.ProcessTrace(handleArray, handleArray.Length,
(FILETIME)startTime, (FILETIME)endTime);
+ System.Diagnostics.Debug.WriteLine("ProcessTrace: " + errorCode);
if (errorCode != ERROR.SUCCESS)
{
errorCode.OutputErrorMessage("TraceConsumer.ProcessTrace");
}
It turns out that the answer was there all along in one of the referencesource files I looked at:
/// ...
/// TreatAsSafe: it generates the GUID that is passed into the TraceProvider
/// WPF versions prior to 4.0 used provider guid: {a42c77db-874f-422e-9b44-6d89fe2bd3e5}
///</SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
static EventTrace()
{
Guid providerGuid = new Guid("E13B77A8-14B6-11DE-8069-001B212B5009");
...
The following simple patch to Sample.RunTrace causes events to start flowing (although they no longer include the particular event which the demo uses for the FPS).
- m_traceSession = TraceController.WpfController;
+ m_traceSession = typeof(System.Windows.Rect).Assembly.GetName().Version.Major == 3
+ ? TraceController.WpfController
+ : TraceController.GetController(new Guid("E13B77A8-14B6-11DE-8069-001B212B5009"), "WPF");
Related
Issue:
I am trying to update the GUI from a second thread.
Unfortunately the label stays the same. At first I thought there is an issue with the dispatcher but it works fine. It appears that the configuration is not threadsafe!
Code to reproduce:
I have a Settings File which is mainly used to keep variables persistent during application relaunches:
this is the Update code:
// get the amount of tickets created for me last week
int amountOftickets = JiraInterface.DayStatisticsGenerator.GetLastWeeksTicketAmount();
config.Default.Lastweekstickets = amountOftickets; // int == 12;
// Update GUI on GUI thread
mainWindow.Dispatcher.Invoke(() =>
{
mainWindow.SetIconsAccordingtoConfig();
mainWindow.NumberTicketsCreated.Content = config.Default.Lastweekstickets.ToString(); // int == 0!!
});
Does anyone have an Idea on how to shove the running configuration from the thread who updated it to the Gui thread?
After a quick look in the documentation, it seems that you have 2 options:
You can either use the Dispatcher.Invoke to set your config.Default
on GUI thread.
It seems that .NET Core and .NET Framework support synchronized SettingsBase which is what the Configs are ( https://learn.microsoft.com/en-us/dotnet/api/system.configuration.settingsbase.synchronized?view=netcore-3.0 )
EDIT 1:
Looking into the C# Properties more, it seems that if you look in your config file in Visual Studio under:
Properties -> Config.settings -> Config.Designer.cs
During the class initialization it seems that .NET Framework, already uses Synhronized property which should make the config thread safe
private static Config defaultInstance = ((Config)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Config())));
It could be that when you created this file, Synchronized wasn't used, so your config file isn't thread safe, especially if it was created in code and not designer/properties
From Microsoft Docs on SettingsBase Synchronized:
The indexer will get and set property data in a thread-safe manner if the IsSynchronized property is set to true. A SettingsBase instance by default is not thread-safe. However, you can call Synchronized passing in a SettingsBase instance to make the SettingsBase indexer operate in a thread-safe manner.
Can you create a .NET 4 version of your app for testing was the bosses' innocent question - sure!
But after I changed our 27 projects in our Winforms application to .NET 4, and recompiled, when launching the app, I get
System.TypeLoadException was unhandled
Message=Inheritance security rules violated while overriding member:
'MyCustomORM.GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'.
Security accessibility of the overriding method must match the security accessibility of the method being overriden.
Hmmm.....
MyCustomORM does indeed implement the ISerializable interface and thus has this method
[Serializable]
public abstract class MyCustomORM: IMyCustomORM, ISerializable, ICloneable, ISecurable
{
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
// do stuff here.......
}
}
and I also have two classes that derive from Exception that override the GetObjectData method.
But what could be wrong here?? Googling around I found some additional attributes to stick onto my method and namespace - so I did:
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)]
namespace MyApplication.ORM
{
[Serializable]
public abstract class MyCustomORM: IMyCustomORM, ISerializable, ICloneable, ISecurable
{
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
// do stuff here.......
}
}
}
but that doesn't change anything.....
The exception happens even before my first line of code in my static Main() method is reached....
I've combed through the project and removed any references to old .NET 1.1 libraries (yes, the app is that old.....) and replaced them with their .NET 4 counterparts (mostly log4net). Still no luck....
Any ideas??
Is the assembly in which the MyCustomORM class resides marked with SecurityTransparentAttribute? If so, the problem stems from changes in the security transparency model between .NET 3.5 and .NET 4.0. For your testing scenario, you may wish to simply opt into using the older transparency mechanism. To do so, add the following assembly-level attribute:
[assembly: SecurityRules(SecurityRuleSet.Level1)]
For more information on the differences between the Level1 and Level2 transparency models, see http://blogs.msdn.com/b/shawnfa/archive/2009/11/12/differences-between-the-security-rule-sets.aspx.
I know this is pretty old, but I ran into this issue with one of my assemblies recently. It only occurred on some machines and was very difficult to determine what was causing it. I didn't just want to put security rule adjustments in, so after much searching I ran across the SecAnnotate tool that is included with Visual Studio.
Using SecAnnotate to Identify Transparency Violations
Using the tool I was able to determine that one of my assemblies was referencing an older version of a dll which contained some security attributes which were causing the problem. Updating the reference fixed the issue.
The SecAnnotate tool seems like a great way to identify any violations that you may have accidentally overlooked or didn't know about.
Hope this helps someone.
We are using the WPF FormattedText object to determine text size in a service that grabs the latest news headlines from an RSS feed. The text retrieved needs to be in a specified canvas size. The service runs the code every 10 seconds and uses up to 2 threads if one takes longer than that. I'm using TaskFactory (which I've overridden the LimitedConcurrencyLevelTaskScheduler to limit to the amount of threads I specified).
This works great, except after several days (the length is variable), we start to get the following exceptions. The same code was working fine before we started using TPL to make it mult-threaded.
I need help figuring out what this is caused by. A few thoughts I'm looking into are: thread collisions holding on to a TTF file, memory issue, the dispatcher (see the stack trace) isn't playing nicely with the TaskFactory, other??
We don't have good profiling setup, but we've looked at the TaskManager when the exception is occurring and memory usage looks normal.
My next attempt is to use the TextBlock object and see if the exception is avoided.
Error Message: The system cannot find the file specified
Error Source: WindowsBase
Error Target Site: UInt16 RegisterClassEx(WNDCLASSEX_D)
Exception Stack Trace:
at MS.Win32.UnsafeNativeMethods.RegisterClassEx(WNDCLASSEX_D wc_d)
at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
at System.Windows.Threading.Dispatcher..ctor()
at System.Windows.Threading.Dispatcher.get_CurrentDispatcher()
at System.Windows.Media.TextFormatting.TextFormatter.FromCurrentDispatcher(TextFormattingMode textFormattingMode)
at System.Windows.Media.FormattedText.LineEnumerator..ctor(FormattedText text)
at System.Windows.Media.FormattedText.DrawAndCalculateMetrics(DrawingContext dc, Point drawingOffset, Boolean getBlackBoxMetrics)
at System.Windows.Media.FormattedText.get_Metrics()
at
(my method using the FormattedText, which is in a loop)
private static Size GetTextSize(string txt, Typeface tf, int size)
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}
EDIT: so far I've tried placing a lock around the code that calls this function, and calling it inside the CurrentDispatcher.Invoke method like so:
return (Size)Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}));
EDIT: I've found links to others having similar, but not the exact problem.
http://www.eggheadcafe.com/software/aspnet/31783898/problem-creating-an-bitmapsource-from-an-hbitmap-in-threaded-code.aspx ~having a similar problem, but no answers
System.Windows.Media.DrawingVisual.RenderOpen() erroring after a time ~having a similar problem, but no answers
http://connect.microsoft.com/VisualStudio/feedback/details/361469/net-3-5-sp1-breaks-use-of-wpf-under-iis# ~ similar exception, but we're not using 3.5SP1 or IIS 7.
I've also submitted this through the Microsoft Connect site (please vote for it if you are having a similar problem).
https://connect.microsoft.com/WPF/feedback/details/654208/wpf-formattedtext-the-system-cannot-find-the-file-specified-exception-in-a-service
EDIT: Response from Microsoft:
"WPF objects need to be created on Dispatcher threads, not thread-pool threads. We usually recommend dedicating a thread to run the dispatcher loop to service requests to create objects and return
them frozen. Thanks, WPF Team" ~ How would I implement this?
EDIT: final solution thanks to NightDweller
if(Application.Current == null) new Application();
(Size)Application.Current.Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
...});
EDIT: When I deployed the change (new Application();), I got an error logged " Cannot create more than one System.Windows.Application instance in the same AppDomain."
Error Source: PresentationFramework
Error Target Site: Void .ctor()
A shot in the dark:
The stack trace seems to show that WPF does not find a Dispatcher in the thread executing GetTextSize, so it has to create a new one, which involves creating a handle to a window.
Calling this every 10 seconds means 8'640 threads, thus windows per day. According to Mark Russinovich, there is a limit of 32 K windows per session, which may explain the error in RegisterClassEx.
An idea to overcome this is to read the current dispatcher from your main thread and set it in your tasks.
Edit:
I had another look and it looks like one cannot set the Dispatcher of a thread (it's created automatically).
I'm sorry, I am unable to understand what is going on here.
In order to compute the text size, WPF needs a FormattedText instance, which is stored as a member of the Dispatcher class. The existing Dispatchers are stored in a list of weak references. Each one is associated with a specific thread.
Here, it looks like new Dispatcher instances are created many, many times.
So, either the calling thread is new or memory is quite low and the weak references have been discarded.
The first case (new thread) is unlikely as the task scheduler uses the thread pool, which has about 25 threads per core (if I remember correctly), which is not enough to deplete the pool of ATOMs or windows.
In the second case, the depletion of resource is unlikely as the HwndWrapper is IDisposable and the Dispose method takes care of freeing the registered class.
As you already know from the info you provided, All UI elements (FormattedText is one) have to be created on the UI thread.
The code you are looking for is:
return (Size)Application.Current.Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}));
Notice the Application.Current - you want the "Application" dispatcher which is the dispatcher for the UI thread in WPF applications.
Your current code actually creates a dispatcher for the current thread so you didn't really change the executing thread (see here regarding the dispatcher)
Have you renamed anything? If yes, check that link: WPF Prism: Problem with creating a Shell
Using the IHtmlDocument2.designMode property set to On to switch a WebBrowser control hosted on a Windows Forms form to editing mode suddenly stopped working after installing Microsoft Internet Explorer 9 RC.
Question:
Any chance to fix this?
I already tried to tweak with doctype or with the EmulateIE7 meta tag but without success.
(An example would be this project)
Update 2011-02-21:
As Eric Lawrence suggested, I adjusted the "Zeta" example to set the document text before setting the edit mode.
Unfortunately I did not manage to switch to design mode, either.
Update 2011-02-24:
Parts of the discussion also take place in Eric's blog.
Update 2011-02-26:
What I currently eperience is that the behaviour seems to be different for HTTP URLs and for content that was added via WebBrowser.DocumentText.
First tests seems to prove this assumption.
I'm now going to build a solution around this assumption and post updates and a proof-of-concept here.
Update 2011-02-26 (2):
I've now built a proof-of-concept with a built-in web server which I believe is also working well with IE 9. If anyone would like to download and test whether it is working and give me a short feedback, I can clean up and release the source code for this.
Update 2011-02-26 (3):
No feedback yet, I still updated the HTML Edit Control article and demo over at the Code Project.
Update 2011-03-16:
Since Internet Explorer 9 was released yesterday, we updated our major products to use the idea with the integrated web server as described in the HTML Edit Control article.
After nearly a month of testing, I think it works quite well.
If you do experience any issues in the future with this approach, please post your comments here and I can investigate and fix.
I had a similar problem and got around it by adding the following line to the DocumentCompleted event:
((HTMLBody)_doc.body).contentEditable = "true";
We just need an empty editable control. I did however step through debugger and add value to the control's InnerHtml and it displayed it fine, and I could edit it.
Small update, we were able to get the control editable using this line also:
browserControl.browser.Document.Body.SetAttribute("contentEditable", "true");
This allows us to avoid referencing mshtml, (don't have to include Microsoft.mshtml.dll)
This lets us avoid increasing our installation size by 8 megs.
What's your exact code?
If I set the following code:
private void cbDesign_CheckedChanged(object sender, EventArgs e){
var instance =
Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(
wbView.ActiveXInstance,
null,
#"Document",
new object[0],
null,
null, null );
var objArray1 = new object[] { cbDesign.Checked ? #"On" : #"Off" };
Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateSetComplex(
instance,
null,
#"designMode",
objArray1,
null,
null,
false,
true );
The IE9 Web Browser instance enters designMode without any problems. If you change the "Zeta" example to not set the document text after entering design mode, it also works fine.
Just want to add that I am also unable to enter designmode (using a WebBrowser control in my case). This was not an issue in the beta. Definitely new with the RC.
Another Code Project user suggested to use the following code:
First, add event DocumentCompleted:
private void SetupEvents()
{
webBrowser1.Navigated += webBrowser1_Navigated;
webBrowser1.GotFocus += webBrowser1_GotFocus;
webBrowser1.DocumentCompleted += this.theBrowser_DocumentCompleted;
}
Then write the function:
private void theBrowser_DocumentCompleted(
object sender,
WebBrowserDocumentCompletedEventArgs e)
{
webBrowser1.Document.Write(webBrowser1.DocumentText);
doc.designMode = "On";
}
Although I did not test this, I want to document it here for completeness.
It's fixed if the property is set after the document is loaded
private void DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
IHTMLDocument2 Doc = Document.DomDocument as IHTMLDocument2;
Doc.designMode = #"On";
}
Yesterday, Internet Explorer 9 RTM finally was released.
I did some more tiny adjustments to my control, but basically the idea with the intergrated, small web server seems to work rather well.
So the solution is in this Code Project article:
Zeta HTML Edit Control
A small wrapper class around the Windows Forms 2.0 WebBrowser control
This was the only solution that worked for me.
I hope it is OK to answer my own question and mark my answer as "answered", too?!?
I was also able to get this to work using the following inside the DocumentCompleted event:
IHTMLDocument2 Doc = browserControl.browser.Document.DomDocument as IHTMLDocument2;
if (Doc != null) Doc.designMode = #"On";
Thanks everyone!
I use HTML Editor Control, I solved this problem adding the DocumentComplete event
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
(((sender as WebBrowser).Document.DomDocument as IHTMLDocument2).body as HTMLBody).contentEditable = "true";
}
Situation: Silverlight 4 app communicating with a server component through WCF, using basicHttpBinding and HTTPS.
Here is the binding used server side:
<basicHttpBinding>
<binding name="DefaultSecuredBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
<readerQuotas maxDepth="50" maxArrayLength="2147483647" maxStringContentLength="2147483647" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
<transport clientCredentialType="None" proxyCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
Notice that we use TransportWithMessageCredential as security mode.
Certificate is correctly installed on IIS.
Application runs smoothly when running locally.
However, we now have external users connecting to our application.
Some of them are experiencing difficulties, and looking inside the server logs, we discovered this error:
"MessageSecurityException"
The security timestamp is stale because its expiration time ('2010-10-18T22:37:58.198Z') is in the past. Current time is '2010-10-18T22:43:18.850Z' and allowed clock skew is '00:05:00'.
We did the usual research on the topics on the web (StackoverFlow & Google... and Bing), to read more on the topic.
We contacted the users to ensure that they were time offset with our server, which was later confirmed.
This MSDN article was the start:
http://msdn.microsoft.com/en-us/library/aa738468.aspx
Which use a CustomBinding over an existing binding and sets the MaxClockSkew property on the SecurityBindingElement of the custom binding.
We implemented this solution, changing however the SymmetricSecurityBindingElement to a TransportSecurityBindingElement, since our binding for secure communication with Silverlight
is basicHttpBinding with HTTPS.
Several articles on the web (including this MSDN article listed above) show code snippets that additionally set the maxClockSkew property to a bootstrap elements taken from ProtectionTokenParameters.
I never succeeded to apply this part in our code, since TransportSecurityBindingElement doesn't seem to have any ProtectionTokenParameters.
Here is our code to wrap a binding with maxClockSkew:
protected virtual System.ServiceModel.Channels.Binding WrapClockSkew(System.ServiceModel.Channels.Binding currentBinding)
{
// Set the maximum difference in minutes
int maxDifference = 300;
// Create a custom binding based on an existing binding
CustomBinding myCustomBinding = new CustomBinding(currentBinding);
// Set the maxClockSkew
var security = myCustomBinding.Elements.Find<TransportSecurityBindingElement>();
if (security != null)
{
security.LocalClientSettings.MaxClockSkew = TimeSpan.FromMinutes(maxDifference);
security.LocalServiceSettings.MaxClockSkew = TimeSpan.FromMinutes(maxDifference);
}
return myCustomBinding;
}
The 'security.LocalClientSettings' may be useless here, since this code is for the server side.
This code didn't do the trick, we still had the same error message on server when we had more than 5 minutes difference with the server.
I still had in mind that we did not apply the bootstrap trick of the MSDN code snippet.. so we continued our web search on the topic.
We found a neat wcf behavior that, we thought, would fix our problem.
It looked like it handles Bootstrap binding matters!
Here is a part where it searches for Token Parameters in a context of a TransportSecurityBindingElement:
//If the securityBindingElement's type is TransportSecurityBindingElement
if (securityBindingElement is TransportSecurityBindingElement)
{
foreach (SecurityTokenParameters securityTokenParameters in
securityBindingElement.EndpointSupportingTokenParameters.Endorsing)
{
//Gets it from the EndpointSupportingTokenParameters.Endorsing property
if (securityTokenParameters is SecureConversationSecurityTokenParameters)
{
secureConversationSecurityTokenParameters =
securityTokenParameters as SecureConversationSecurityTokenParameters;
break;
}
}
}
Note the 'securityBindingElement.EndpointSupportingTokenParameters.Endorsing'...
In our situation (basicHttpBinding, TransportWithMessageCredential, Https...), this collection is however empty!
So, no way to retrieve the securityTokenParameters, thus impossible to set the maxClockSkew.
Questions:
Are our bindings incorrect in a SL + WCF + HTTPS context?
Is it normal to not find any way to set the maxClockSkew on a bootstrap element in a TransportSecurityBindingElement?
Are we the only company doing HTTPS Silverlight app with customers that might not be on the exact same time (with +- 5 minutes offset) ?
Why does it seem to be quite an adventure to fix such trivial configuration?
Any help would be appreciated!
The following code snippet lets you set the maxClockSkew on the TransportSecurityBindingElement. My solution is an Outlook Add-in + WCF operating in http and https contexts, so although not the same context as yours its similar.
Your bindings look correct to me.
Here's the code snippet
WSHttpBinding wsSecureBinding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential, false);
wsSecureBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
wsSecureBinding.Security.Message.EstablishSecurityContext = true;
wsSecureBinding.Security.Message.NegotiateServiceCredential = true;
wsSecureBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
wsSecureBinding.ReaderQuotas.MaxStringContentLength = 500000;
wsSecureBinding.ReceiveTimeout =
wsSecureBinding.SendTimeout = new TimeSpan(0, 5, 0);
CustomBinding secureCustomBinding = new CustomBinding(wsSecureBinding);
TimeSpan clockSkew = new TimeSpan(0, 15, 0);
TransportSecurityBindingElement tsecurity = secureCustomBinding.Elements.Find();
SecureConversationSecurityTokenParameters secureTokenParams = (SecureConversationSecurityTokenParameters)tsecurity.EndpointSupportingTokenParameters.Endorsing.OfType().FirstOrDefault();
if (secureTokenParams != null)
{
SecurityBindingElement bootstrap = secureTokenParams.BootstrapSecurityBindingElement;
// Set the MaxClockSkew on the bootstrap element.
bootstrap.LocalClientSettings.MaxClockSkew = clockSkew;
bootstrap.LocalServiceSettings.MaxClockSkew = clockSkew;
}
The clock skew only matters as you are using UserName client credentials and some users either like their computer clocks not being the correct time, or they don't care
Yes, WCF configuration is always an adventure you'd rather not do.
We are running into the same problem here!!! For further discussion, if this post can help, the code where it searches for Token Parameter is taken from this site
http://issues.castleproject.org/_persistent/MaxClockSkewBehavior.cs?file=44-1075&v=0&c=true
Have you tried changing to custom binding in config (instead of code) and changing maxClockSkew there? See e.g. config samples in http://social.msdn.microsoft.com/forums/en-US/wcf/thread/0e8c30ab-e5a0-40b1-9722-c1b20a09c8ad/