I have an asmx method that accepts a list of files like so:
[WebMethod]
public void UploadFiles(List<byte[]> files)
{
}
The Windows metadata is not included in the byte array. I tried using Dictionary<filename, byte[]> but classes that implement IDictionary are not serializable. I also tried using KeyValuePair<string, byte[]>[] but IMO it looks dirty.
Are there other ways to include the name of the file?
As mentioned in the comments, this can easily resolved by making a custom data class.
It's unfortunate that Dictionaries aren't serializable, but it's an inherent flaw of the XML serialization process. Same goes for data classes with circular references, it just doesn't work.
WCF, however, has managed to fix those issues. But you're using .asmx (SOAP), so you're stuck with the unfortunate incompatibility.
I'd simply make a custom class:
[Serializable]
public class File
{
public string FileName {get;set;}
public byte[] Payload {get;set;}
}
Then change your web method to:
[WebMethod]
public void UploadFiles(List<File> files)
{
//...
}
Simple, but effective :)
Related
I'm trying to use a class on Access VBA 7.0 which implements an Interface I made and I'm still getting "Automation error" even after adding the usual headers.
DropBox.cs
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("E2F07CD4-CE73-4102-B35D-119362624C47")]
[ComDefaultInterface(typeof(ICloudFileProvider))]
[ProgId("CloudFiles.dll")]
public class DropBox : ICloudFileProvider
{
public DropBox()
{
ConectaDropbox("TokenLongChicken");
}
public DropBox(string tokenUsuario)
{ //This was the original and good constructor. I know I can't use constructors with arguments on VBA. Just keeping it to compile with Test
ConectaDropbox(tokenUsuario);
}
public void ConectaDropbox(string tokenUsuario)
{
}
// This method and others come implemented from an interface (ICloudFileProvider)
public string SubirArchivo(string rutaLocal, string carpetaCloud, Tipos.TipoSobreescritura tipoSobreescritura)
{
}
This didn't work, so I saw I have to "create" a header for the Interface and I did it on the Interface itself. I'm still getting the error, so on the DropBox class, I added another header "enumerating" the methods I'm using on this class (which has no sense, but I've read another questions on SO which concretes you have to do so).
So I added this at the end of the DropBox class, noting it is as well on the ICloudFileProvider Interface (the real one).
[ComVisible(true)]
[Guid("E2F11CD4-CE73-4102-B35D-119362624C47")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IExposedClass
{
void DropBox();
void DropBox(string tokenUsuario);
void ConectaDropbox(string tokenUsuario);
string SubirArchivo(string rutaLocal, string carpetaCloud, Tipos.TipoSobreescritura tipoSobreescritura);
decimal ConvertBytesToMegabytes(long bytes);
void Descargar(string link, string carpetaLocal);
string GenerarLink(string rutaCloud);
void EliminarArchivo(string link);
}
I guess I'm doing something wrong but I'm kind of lost in this DLL and TLB hell. This project just works fine on C# but I need to integrate it on VBA and I see no examples with projects which uses real interfaces. I'm not really sure if the "InterfaceIsIUnkown" I add at the end of the DropBox class makes any sense, but I saw it on every example I found on the Internet (but none of them used a real Interface).
Could anybody help? Thanks.
P.S: yes, I perform the RegAsm.exe export to .TLB and then I add it to my Access, with no export errors apparently.
I have a separate Module in a C# class library project which is loaded via MEF Imports.
As an initial attempt at bringing sitemap information along with the Module I have added a web.sitemap file with the necessary mark-up but I can't seem to get a clear sense of how to load it and attach it to the Host MVC project sitemap in memory.
I also tried to use an MvcSiteMapNode attribute but haven't really been able to get this working yet.
Firstly, which is the easiest method to use, Attribute or SiteMap?
Secondly can anyone point me to guidance on how to do either of these please?
I have a preference for using the sitemap file because it should avoid dependencies on MvcSiteMapProvider in the MEF module.
You could embed XML into your modules and then somehow export them through MEF, I am pretty sure that is an option.
To load the XML from memory, you will need to use an external DI container and implement the IXmlSource interface yourself.
public class MyXmlSource : IXmlSource
{
public XDocument GetXml()
{
// Load the XML from wherever...
}
}
Then the DI configuration would just need to swap out the default XmlSource.
var excludeTypes = new Type[] {
typeof(IXmlSource)
};
// More DI config not shown...
this.For<IXmlSource>()
.Use<MyXmlSource>();
Of course, if you have multiple files, you would need multiple registrations of IXmlSource and XmlSiteMapNodeProvider. The XmlSiteMapNodeProvider only has the ability to merge the nodes below the root node, so you can't just place them anywhere in the SiteMap.
XML and Attributes are the least flexible options for configuring MvcSiteMapProvider.
Another Approach
The most flexible option is to use ISiteMapNodeProvider implementations to load your configuration data which also requires an external DI container. The second-best option is to use dynamic node provider implementations, but the limitation there is that they cannot contain the root node and require either an XML node or .NET attribute to host the provider on.
However, if you don't want any 3rd party dependencies, you will need a custom abstraction (DTO) that is defined in your own base library that is exported via MEF, and then used by either ISiteMapNodeProvider or IDynamicNodeProvider to load the data from the abstraction.
public class SiteMapNodeDto
{
public string Key { get; set; }
public string ParentKey { get; set; }
public string Title { get; set; }
public IDictionary<string, object> RouteValues { get; set; }
// Additional properties...
}
And then have an interface of some kind that your module can implement to provide nodes.
public interface IModuleSiteMapNodeProvider
{
IEnumerable<SiteMapNodeDto> GetNodes();
}
My brief experience with MEF was several years ago, so I don't recall how you export a type and import it somewhere else, so you will need to work that out on your own.
Then in your main application, you could create a method for converting from your DTO to the type that is expected by MvcSiteMapProvider (ISiteMapNodeToParentRelation or DynamicNode).
public static SiteMapNodeProviderExtensions
{
public static ISiteMapToParentRelation CreateNode(this ISiteMapNodeHelper helper, SiteMapNodeDto dto, string sourceName)
{
string key = helper.CreateNodeKey(
dto.ParentKey,
dto.Key,
dto.Url,
dto.Title,
dto.Area,
dto.Controller,
dto.Action,
dto.HttpMethod,
dto.Clickable);
var nodeParentMap = helper.CreateNode(key, attribute.ParentKey, sourceName);
var node = nodeParentMap.Node;
node.Title = title;
// Populate remaining properties...
return nodeParentMap;
}
}
And then in the ISiteMapNodeProvider you would simply need to call this method for each node.
public IEnumerable<ISiteMapNodeToParentRelation> GetSiteMapNodes(ISiteMapNodeHelper helper)
{
string sourceName = typeof(SiteMapNodeDto).Name;
IEnumerable<SiteMapNodeDto> dtos = someExternalSource.GetNodes();
foreach (var dto in dtos)
{
yield return helper.CreateNode(dto, sourceName);
}
}
If you want to make providing SiteMap nodes a first class feature for your module developers (and make it really easy to understand the hierarchy of nodes like you can with XML), you could create a Fluent API so you can express the nodes in code. Have a look at this pull request for one such approach.
We are implementing a plug and play module for our application where user can load and unload the desired class library at runtime. So I have decided to use MEF and shadow copying of class libraries.
The thing here is each class library may have different configuration properties which needs to set by user. My main application has no knowledge about the configurations present in the class library.
Now the problem is when I try to transfer the application configuration file loaded with class library from one application domain to another.
Without MEF, I have just returned Settings.Default from the class library and I have used it in our main application to edit the settings. With MEF and shadow copying, It doesn't seems to be working because
The object type needs to known to both sides.
I cannot implement MarshalByRefObject on the settings file since
the settings file is already extending ApplicationSettingsBase which
is an abstract class and c# doesn't supports multiple inheritance.
Currently I am creating a class which holds all the properties as string and creating a GUI in my main application based on this class content.
public class ExtensionModuleConfiguration : MarshalByRefObject
{
public string Name { get; set; }
public string Value { get; set; }
public List<string> Options { get; set; }
public UIElements ToolUIElement { get; set; }
}
public enum UIElements
{
ComboBox,
TextBox
}
I must say this is not the best solution.
Can someone suggest a better way to set the configurations of a class library in MEF?
There two ways how you can do it. You must inform .NET which app.config should be loaded in the appdomain of your MEF plugin class.
Therefore you can either point particular app.config for your plugin DLL like this:
ConfigurationManager.OpenExeConfiguration("Plugin.dll");
var name = AppSettings.Settings["Name"].Value;
Or you can load the app.config for your main application DLL and put all the appsettings in that file. In this case you should do:
var config = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
var name = config.AppSettings.Settings["Name"].Value;
Both solutions should be called from within of you Plugin implementation for example in constructor. Or by first call to some lazy loaded configuration property.
I am trying to extend my CreateConnectionId function to add custom logic when creating ConnectionId's in signalR
public class MyConnectionFactory : IConnectionIdFactory
{
public string CreateConnectionId(IRequest request){
//Code Goes Here
}
}
but IConnectionIdFactory will not be resolved in my intellisense because it cannot find it in my assembly. I have the following References in my References folder:
SignalR, SignalR.Hosting.AspNet, SignalR.Ninject
It was renamed in a recent version. The IConnectionIdFactory interface was renamed to IConnectionIdGenerator.
You can find the interface under the SignalRnamespace.
Your code should look like this instead:
public class MyConnectionFactory : IConnectionIdGenerator
{
public string GenerateConnectionId(IRequest request)
{
return "some generated ID";
}
}
I'm guessing you're looking at some old samples somewhere? What version of SignalR are you referencing? I believe that's a rather old interface pre-dating the MessageBus rework that was done. I believe the interface you're looking for now is IIdGenerator.
My current solution has 3 project with 2 app.config (one for common settings and another for service settings). As of now I'm simply creating static classes to act as a mediator to access values. I do this so I don't have to write ConfigurationManager.AppSettings["SomeKey"] everywhere. This works fine until you want to access an app.config file from a different project.
Here is what I'm currently doing (all properties omitted for brevity).
public class ServiceConfiguration
{
public static readonly string SyncEvery = ConfigurationManager.AppSettings["SyncEveryMinutes"];
}
How can I access an app.config file located in another project? I thought perhaps setting VS to copy the file to the output directory would do the trick however my configuration object is still null.
I can't imaging many good reasons to read another app's configuration in the first place, it just opens a can of worms that isn't worth dealing with.
Expose a class that exposes the project's configured values as properties, and access them from a consuming class.
public class FirstProjectClass
{
public static int SyncEveryMinutes
{
get { return (int)ConfigurationManager.AppSetting["SyncEveryMinutes"] };
}
}
public class SecondProjectClass
{
public void ShowConfigedValue()
{
Console.Writeline("Syncing every {0} minutes", FirstProjectClass.SyncEveryMinutes);
}
}
if you've got complex configuration requirements you can also look into custom configuration sections
ConfigurationManager.OpenExeConfiguration can be helpfull:
http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.openexeconfiguration.aspx
Also: what Jason said - it is usually a bad idea.