DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. Data
  4. Adding Multiple Data Importers Support To Web Applications

Adding Multiple Data Importers Support To Web Applications

Gunnar Peipman user avatar by
Gunnar Peipman
·
Aug. 24, 12 · Interview
Like (0)
Save
Tweet
Share
3.42K Views

Join the DZone community and get the full member experience.

Join For Free

I’m building web application for customer and there is requirement that users must be able to import data in different formats. Today we will support XLSX and ODF as import formats and some other formats are waiting. I wanted to be able to add new importers on the fly so I don’t have to deploy web application again when I add new importer or change some existing one. In this posting I will show you how to build generic importers support to your web application.

Importer interface

All importers we use must have something in common so we can easily detect them. To keep things simple I will use interface here.

public interface IMyImporter
{
    string[] SupportedFileExtensions { get; }
    ImportResult Import(Stream fileStream, string fileExtension);
}

Our interface has the following members:

  • SupportedFileExtensions – string array of file extensions that importer supports. This property helps us find out what import formats are available and which importer to use with given format.
  • Import – method that does the actual importing work. Besides file we give in as stream we also give file extension so importer can decide how to handle the file.

It is enough to get started. When building real importers I am sure you will switch over to abstract base class.

Importer class

Here is sample importer that imports data from Excel and Word documents. Importer class with no implementation details looks like this:

public class MyOpenXmlImporter : IMyImporter
{
    public string[] SupportedFileExtensions
    {
        get { return new[] { "xlsx", "docx" }; }
    }
    public ImportResult Import(Stream fileStream, string extension)
    {
        // ...
    }
}

Finding supported import formats in web application

Now we have importers created and it’s time to add them to web application. Usually we have one page or ASP.NET MVC controller where we need importers. To this page or controller we add the following method that uses reflection to find all classes that implement our IMyImporter interface.

private static string[] GetImporterFileExtensions()
{
    var types = from a in AppDomain.CurrentDomain.GetAssemblies()
                from t in a.GetTypes()
                where t.GetInterfaces().Contains(typeof(IMyImporter))
                select t;
 
    var extensions = new Collection<string>();
    foreach (var type in types)
    {
        var instance = (IMyImporter)type.InvokeMember(null,
                      BindingFlags.CreateInstance, null, null, null);
 
        foreach (var extension in instance.SupportedFileExtensions)
        {
            if (extensions.Contains(extension))
                continue;
 
            extensions.Add(extension);
        }
    }
 
    return extensions.ToArray();
}

This code doesn’t look nice and is far from optimal but it works for us now. It is possible to improve performance of web application if we cache extensions and their corresponding types to some static dictionary. We have to fill it only once because our application is restarted when something changes in bin folder.

Finding importer by extension

When user uploads file we need to detect the extension of file and find the importer that supports given extension. We add another method to our page or controller that uses reflection to return us importer instance or null if extension is not supported.

private static IMyImporter GetImporterForExtension(string extensionToFind)
{
    var types = from a in AppDomain.CurrentDomain.GetAssemblies()
                from t in a.GetTypes()
                where t.GetInterfaces().Contains(typeof(IMyImporter))
                select t;
    foreach (var type in types)
    {
        var instance = (IMyImporter)type.InvokeMember(null,
                      BindingFlags.CreateInstance, null, null, null);

        if (instance.SupportedFileExtensions.Contains(extensionToFind))
        {
            return instance;
        }
    }
 
    return null;
}

Here is example ASP.NET MVC controller action that accepts uploaded file, finds importer that can handle file and imports data. Again, this is sample code I kept minimal to better illustrate how things work.

public ActionResult Import(MyImporterModel model)
{
    var file = Request.Files[0];
    var extension = Path.GetExtension(file.FileName).ToLower();
    var importer = GetImporterForExtension(extension.Substring(1));
    var result = importer.Import(file.InputStream, extension);
    if (result.Errors.Count > 0)
    {
        foreach (var error in result.Errors)
           ModelState.AddModelError("file", error);
 
        return Import();
    }
    return RedirectToAction("Index");
}

Conclusion

That’s it. Using couple of ugly methods and one simple interface we were able to add importers support to our web application. Example code here is not perfect but it works. It is possible to cache mappings between file extensions and importer types to some static variable because changing of these mappings means that something is changed in bin folder of web application and web application is restarted in this case anyway.

Importer (computing) Web application Data (computing)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • What Was the Question Again, ChatGPT?
  • How to Submit a Post to DZone
  • API Design Patterns Review
  • Microservices Discovery With Eureka

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: