I'm working with pre-defined IOrganizationService object I cannot modify — it's out of my control.
And it seems to be by default this IOrganizationService returns resolved types as if EnableProxyTypes() was called implicitly somewhere on originating OrganizationServiceProxy.
And this ruins all business logic, since early bound entities could not be serialized that easily, since on different installations they could be resolved to different types. So even if they would be successfully serialized, cannot be 100% certain that they could be de-serialized.
To be more specific it's plugin for XrmToolBox. If hosting application loaded plugin that uses early bounding, these generated types will be discovered via reflection and applied to results of Retrieve and RetrieveMultiple calls.
For example RetrieveMultiple to account entity response will normally contain Entity[], each item of this array will have LogicalName property set to account.
But if early bound types was discovered in assembly, let's call it EarlyBouldLibrary.dll, the same RetrieveMultiple will return EarlyBouldLibrary.Account[]. Each item of this array will be derived from Entity and will contain same field as in first example, but with additional properties.
The problem is in following. If we will try to serialize EarlyBouldLibrary.Account[] to XML it will fail. Because EarlyBouldLibrary.Account is unknown.
Ok, it's possible to add types to known. But there is no guarantee, that one day another early bound types will be found in NewEarlyBouldLibrary.dll... And they will have name NewEarlyBouldLibrary.Account... Which is unknown...
Ok, let's assume serialization succeeded, no matter which types are referenced EarlyBouldLibrary.Account or NewEarlyBouldLibrary.Account, but if we will try to de-serialize, on environment where these early bound libraries not present... action will fail.
So only way will be not to use specific early bound types, that out of our control, and use standard and safe Entity. But it's impossible while system automatically resolves proxy types.
So, question: is there any way to disable resolve of early bound types?
You can redirect your proxy to another assembly containing the types you need (or even containing no early bound types at all).
The example below resets the proxy assembly:
private void ResetProxyAssembly(IOrganizationService service)
{
var serviceProxy = (OrganizationServiceProxy) service;
serviceProxy.EnableProxyTypes();
}
In certain scenarios this may not work. Instead you can explicitly select the desired proxy assembly:
private void ResetProxyAssembly(IOrganizationService service)
{
var serviceProxy = (OrganizationServiceProxy) service;
serviceProxy.EnableProxyTypes(typeof(MyEarlyBoundEntity).Assembly);
}
Could you add [assembly: Microsoft.Xrm.Sdk.Client.ProxyTypesAssembly] to the AssemblyInfo file of the EarlyBouldLibrary.dll or NewEarlyBouldLibrary.dll assembly?
Related
I'd be grateful if you could help with this:
I have a base class for a Provider.
This is subclassed to create a
DefaultProvider.
DefaultProvider implements an interface called “IExportProvider”
DefaultProvider is subclassed to create a
DanishProvider.
The base class has various virtual methods that return string values in English.
The DanishProvider overrides these to return strings in Danish.
At runtime, I load either the DefaultProvider or the DanishProvider depending on a config. value. I do this by scanning the current assembly for the type name, which is either “DefaultProvider” or “DanishProvider”, and which implements “IExportProvider”
var importServiceType = assembly.DefinedTypes.FirstOrDefault(type => (type.Name.Equals(providerServiceName, StringComparison.OrdinalIgnoreCase)) && type.ImplementedInterfaces.Any(i => i == typeof(I)));
I then use Activator.CreateInstance to create an instance of the type:
return (IExportProvider)Activator.CreateInstance(importServiceType, …)
Problem
I use the code in a .Net 4.8 Web application, where I load the DanishProvider. This mostly works OK and I can see the Danish strings are returned. However, occasionally (after several days) the application appears to incorrectly load the DefaultProvider, and I see English strings returned.
Once it has switched to English it appears to stay on the DefaultProvider.
Twice I have done an IISRESET which fixes the problem immediately.
The settings
are not being changed.
There is only one type in the assembly called “DanishProvider”
The code is executing on a single UAT server. I have not seen the issue on my local PC.
I do not believe that the issue is related to caching.
Q. Is there a problem with the code approach described above?
Thank you
I have an application and I'm using MEF to compose it. I want to know if it is possible to update the Metadata information of the parts after they were imported.
The reason to do this is the following: I display the imported parts' name and an typeof(int) property in a ListBox, and they are not loaded until the corresponding ListBoxItem is selected (pretty standard). Now I want to update the Metadata info of one part when some event raises, so the displayed info in the ListBox is somethind like "[Part name] ([new number])".
I'm importing the metadata as an Interface that defines it's info, but when I set the int property to be editable (with a set accesor) I receive the following execption at composition time:
"The MetadataView 'myMetadataInterface' is invalid
because property 'myInt' has a property set method."
Is there ANY way to achieve this? Or is the metadata ALWAYS read only once the part is created?
I know this question looks weird, but it doesn't make it any less difficult and therefore interesting ;-)
EDIT (based on Lee's answer, in order to keep people to the core of the question)
I just want to know if it is possible to update a Metadata property after the part is composed, but before it is actually loaded (HasValue == false). Don't worry about filtering or finding the part.
I added a property to the export inteface, which is meant only to be represented in the UI and to be updated, this property has no other function and the parts are not filtered by it.
Thanks
Metadata filtering and DefaultValueAttribute
When you specifiy a metadata view, an implicit filtering will occur to
match only those exports which contain the metadata properties defined
in the view. You can specify on the metadata view that a property is
not required, by using the
System.ComponentModel.DefaultValueAttribute. Below you can see where
we have specified a default value of false on IsSecure. This means if
a part exports IMessageSender, but does not supply IsSecure metadata,
then it will still be matched.
citation
Short Version (EDITED in after question edit).
You shouldn't ever need to update metadata at runtime. If you have some data that should be updated and belongs to a mef part, you need to choose to either have it be updated by recompiling, or store that data in a flexible storage outside of the dll. There's no way to store the change you made in the dll without recompiling, so this is a flawed design.
Previous post.
Altering values on the view would by lying about the components loaded. Sure the metadata is just an interface to an object that returns initialized values; sure you can technically update those values, but that's not the purpose of metadata.
You wouldn't be changing the Name field of an instance of Type. Why not? Because it's metadata. Updating metadata at runtime would imply that the nature of the instance of real data is somehow modified.
This line of code, if possible, wouldn't introduce the Triple type.
typeof(Double).Name = "Triple";
var IGotATriple = new Triple();
If you want to alter values, you need to just make another object with that information and bind to that. Metadata is compiled in. If you change it after a part is loaded, it doesn't change anything in the part's source, so you'd be lying. (unless you're going to have access to the source-code and you change it there and recompile).
Let's look at an example:
[Export(typeof(IPart))]
[ExportMetadata("Part Name","Gearbox")]
[ExportMetadata("Part Number","123")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class GearBoxPart : Part { public double GearRatio ... }
Now, let's assume that you had a UI that showed available parts and their numbers. Now, the manufacturer changes the part number for whatever reason and you want to update it. If this is possible, you might want to consider storing part number in a manifest or database instead. Alternatively you'd have to recompile every time a part number changes.
Recompile is possible. You have a controller UI that does the above, but instead of updating the metadata, you submit a request to rebuild the part's codefile. The request would be handled by parsing the codefile, replacing the part number, then sending off for a batch recompile and redistribute the new dll. That's a lot of work for nothing IMO.
So, you setup a database. Then you change the object metadata to this.
[ExportMetadata("OurCompanyNamePartNumber","123")]
Then you have a database/manifest/xml that maps your unique permanent static part number that your company devises to the current part number. Modifications in your control UI update the database/manifest/xml.
<PartMap>
<PartMapEntry OurCompanyNamePartNumber="123" ManufacturerPartNumber="456"/>
...
</PartMap>
Then the end-user UI does lookups for the part by manufacturer part number, and the mef code looks in the PartMap to get the mef part number.
I'm writing some service.
I'm asking 2 questions regarding 2 situations:
Situations
1) i use it "in-house", meaning as a referenced dll
2) I use it over the net, as webService
Questions
A)
If it exposes an interface to some client-class.
and now I added some method to that interface.
Do I have to recompile all its clients to recognize
the new interface even if they don't use the new methods?
B)
If a method in my service's interface expect some PoCo with property a,b
and one of the client calls that method with the same Poco type, but this Poco is defiened in the client-code as one that has a,b as before and also c,d.
Do I have to recompile the service? Does the contract breaks?
For web services, if you are certain that changes will happen, you may want to design a 'versioned' interface that takes generic arguments and a version number. I have done this using an XML string that holds the contents of the parameters passed (XML string passed to web service a HTML encoded to avoid breaking SOAP envelope).
In the web service methods, checking the version number than proceeds to parse the XML into the expected type(s) for that method:
public void GenericWebServeceMethod(int version, string encodedXMLParameters)
{
string xmlParameters = HTMLDecode(encodedParameters);
switch(version)
{
case 1:
ParameterType1 p1 = DecodeVersion1XML(xmlParameters);
MethodVersion1(p1);
break;
case 2:
ParameterType2 p2 = DecodeVersion2XML(xmlParameters);
MethodVersion2(p2);
break;
}
}
When new versions are added, you extend the switch statement with new versions which still allows clients using older versions of the parameter types to continue working.
For a referenced DLL used 'in-house' you can force the reference to be version independent by adding the reference using the 'Browse' option in Visual Studio, and then selecting the reference's properties and ensuring that the 'Specific Version' property is set to False. Then you can still use a system similar to above to change the way than XML-encoded parameters are handled based on a passed version number. Adding new methods is allowed but the calling client will not 'see' them until it it recompiled.
I created a WCF service.in my data contract I have two attributes lets say:
[DataMember]
Private User objUser;
and
[DataMember]
Private tempClass ObjTemp;
I have get and set property for both the attributes. In my implementation class, I have an object of datacontract class... lets say. objData.
When I assign
objData.ObjTemp=(function which return objTemp);
the service work fine. But, when I assign.
objData.objUser=(function which return objUser)
it throws following error:
The underlying connection was closed: The connection was closed
unexpectedly.
When I comment
objData.objUser=(function which return objUser)
it works fine again.
When I inspect the code inside my User class, I found one property creating problem. When I change the property that property it works fine too; but i do not know why that property is creating problem.
The property is like this:
public IPAddress IP { get; set; }
Now this IPAdress class contains a constructor, and get and set for ip variable. In the get, it simply returns ip variable.
in set it checks some condition and then assign value to ip variable. If condition fails, it throws an exception. Can anybody explain what the problem could be?
I just checked another thing.
If i remove [DataMember] attribute from private User objUser; it works fine; but if i put [DataMember] back it generates the same error.
any suggestions?
You will most likely find that objUser is not serializable. For more info read this: MSDN: Using Data Contracts
To quote a short snippet of that:
All .NET Framework primitive types, such as integers and strings, as well as certain types treated as primitives, such as DateTime and XmlElement, can be serialized with no other preparation and are considered as having default data contracts.... New complex types that you create must have a data contract defined for them to be serializable.
You could also consider using the Service Trace Viewer tool from Microsoft to help track down the exact problem you are having.
Edit:
if it is the System.Net.IPAddress object you are talking about, then it is marked as [Serializable], but it doesn't have a default parameterless constructor, which is one of the requirements necessary when using the DataContractSerializer (which is what is used to serialize your data objects over the WCF boundary). You may also want to ensure that if any of your custom objects used in your WCF calls contain any further custom objects (in properties, like your IPAddress) then they are decorated with the KnownType attribute.
So, as a solution you can either write your own IPAddress class that plays nice with the DataContractSerializer, or switch to using the XmlSerializer in your WCF calls.
We are using a Microsoft ERP which dynamically exposes web services. The services generated by the service is out of our control. We have no say so in how the objects, including the type definitions, are created and exposed. When a new method is added or removed from the web service, all of the type enumerations are renumbered and everything that uses the web service, after updating to the new definitions, is hosed up. So essentially,
enumeration Type1
Item1
Item2
Item3
... could become
enumeration Type6
Item1
Item2
Item3
...with the enumeration type name changing, but members of the type remaining static. The service outputs a service which looks exactly like the end result of using the XSD.exe to generate objects. So anytime someone exposes a new method on the service (via the ERP GUI), the objects are rebuilt, types are assigned to the service definitions in alphabetical order, reexposed, leaving the entire code base shot.
I attempted to use reflection to determine the type and then parse out the static member into the new business object, but it doesn't work because I can't type cast the enumeration without knowing the actual name of the type. The following won't work.
System.Type t = service.BusinessObjectEnumeration.GetType();
service.SomeField = Enum.Parse(t,"Item1");
...as the compiler throws an error because I'm not explicitly casting the enumeration.
Any ideas how I can overcome this issue while dynamically casting the type to the correct enumeration?
Again, I cannot modify the actual objects exposed by the service, only the code subscribing to the service.
Re the example code:
System.Type t = service.BusinessObjectEnumeration.GetType();
service.SomeField = Enum.Parse(t,"Item1");
Maybe the way to do this is via reflection:
var prop = service.GetType().GetProperty("SomeField");
prop.SetValue(service, Enum.Parse(prop.PropertyType, "Item1"), null);
I had a similar issue with Nav web services. The solution I used to to create a new web reference for each service you expose through Nav rather than just a single one for all services. This prevents the name collisions you are experiencing without using reflection or hacks.
Why should you need to parse things?
If I understand Enums correctly, they pass on the value (and not the Enum itself).
EDIT: What I mean is, enum is not same as a class. For a class, one expects an instance to be passed/received. For an enum, it is one or combination of its members, which is passed in form of an int value.
EDIT2: Are you trying to use the enum as some kind of struct here?
EDIT3: You will have to see what type is the enum in debug mode, to figure out how to reflect on it.
object enumValueReturned = service.BusinessObjectEnumeration;
Put the enumValueReturned in watch window & play with it using reflection (GetMembers) to see, how would you reach Item1.