Friday, August 24, 2018

Do multiple registrations of IFilterProvider still work in MVC5?

I am sure that this code used to work. I have a UnityFilterProvider and a UnityGlobalFilterProvider both registered in my Unity config.

I would have expected it to pick up both IFilterProviders, but if they are both registered it will only pick up the GlobalFilterProvider. If the only one registered is the basic UnityFilterProvider then that works fine.

But I cannot get them both working together.

Am I doing something wrong? Did this used to work, but not in MVC5? Did this never work and should I do something different?

UnityFilterProvider.cs

namespace Website.Infrastructure
{
    public class UnityFilterProvider : FilterAttributeFilterProvider
    {
        private IUnityContainer container;

        public UnityFilterProvider(IUnityContainer container)
        {
            this.container = container;
        }

        public override IEnumerable GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            var filters = base.GetFilters(controllerContext, actionDescriptor);

            foreach (var filter in filters)
            {
                container.BuildUp(filter.Instance.GetType(), filter.Instance);
            }

            return filters;
        }
    }
}

UnityGlobalFilterProvider.cs

namespace Website.Infrastructure
{
    public class UnityGlobalFilterProvider : IFilterProvider
    { 
        private readonly IUnityContainer container;
        private readonly IGlobalFilterRegistrationList filterList;

        public UnityGlobalFilterProvider(IUnityContainer container, IGlobalFilterRegistrationList filterList)
        {
            this.container = container;
            this.filterList = filterList;
        }

        public IEnumerable GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            var filters = new List();
            if (filterList == null || filterList.Count == 0)
                return filters;

            foreach (GlobalFilterRegistration registration in filterList)
            {
                var actionFilter = container.Resolve(registration.Type);
                var filter = new Filter(actionFilter, FilterScope.Global, registration.Order);
                filters.Add(filter);
            }

            return filters;
        }
    }

    public class GlobalFilterRegistration
    {
        public GlobalFilterRegistration(Type type, int? order)
        {
            this.Type = type;
            this.Order = order;
        }

        public Type Type { get; set; }
        public int? Order { get; set; }
    }

    public class GlobalFilterRegistrationList : List, IGlobalFilterRegistrationList
    {
    }

    public interface IGlobalFilterRegistrationList
    {
        int Count { get; }
        List.Enumerator GetEnumerator();
        void Add(GlobalFilterRegistration item);
    }
}

UnityConfig (snip)

container.RegisterType(new ContainerControlledLifetimeManager());
container.RegisterType(new ContainerControlledLifetimeManager());
container.RegisterType(
    new ContainerControlledLifetimeManager());

Anyone got any ideas?

Adding names to the provider registrations solved the problem

container.RegisterType("UnityFilterProvider", new ContainerControlledLifetimeManager());
container.RegisterType("UnityGlobalFilterProvider", new ContainerControlledLifetimeManager());

Solved

Adding names to the Filter registrations solved the problem.

    container.RegisterType("UnityFilterProvider", new ContainerControlledLifetimeManager());
    container.RegisterType("UnityGlobalFilterProvider", new ContainerControlledLifetimeManager());

Cheers Mike


Probably this is due to the way the filters being registered. The works for me.

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        var container = new UnityContainer();
        container.RegisterType(new ContainerControlledLifetimeManager());
        container.RegisterType(new ContainerControlledLifetimeManager());
        container.RegisterType(
            new ContainerControlledLifetimeManager());

        container.RegisterType();
        container.RegisterType();

        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

        GlobalFilters.Filters.Add(new SomeGlobalFilterAttribute());

        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

    }
}

public interface I
{ }

public class C : I
{ }


public class SomeGlobalFilterAttribute : ActionFilterAttribute
{
    [Dependency]
    public I C { get; set; }
    public SomeGlobalFilterAttribute()
    {

    }
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var c = C;
        base.OnActionExecuting(filterContext);
    }
}

public class SomeActionFilterAttribute : ActionFilterAttribute
{
    [Dependency]
    public I C { get; set; }
    public SomeActionFilterAttribute()
    {

    }
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var c = C;
        base.OnActionExecuting(filterContext);
    }
}

Monday, August 20, 2018

Android: HttpPost JSON string in UTF-8 encoding to PHP

This is a follow up question to Android with php: Saving utf-8 string to MySQL

I am using the Gson library in Android to convert a class instance to a JSON string. This JSON string is then uploaded with HttpPost to a PHP script to save it to my MySQL DB.

Initialy I thought the problem was with php or MySQL, but it now appears to be my HttpPost code sequence not properly encoding the JSON to UTF-8. If I debug my code and do a POST from within Chrome with JSON string, it works perfectly.

My MySQL DB is now formatted as UTF-8 (utf8_general_ci).

Here is my HttpPost code:

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);

ArrayList parameters = new ArrayList();
parameters.add(new BasicNameValuePair("questionnaire", json));

httppost.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8"));

HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();

The problem might be in httppost.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8")); , but I am not sure how else to inform my PHP script that I am sending JSON in UTF-8 format.

As an example "can't get there" is correctly encoded by Android as "can/u0027t get there" when the JSON strig is created by Gson. After uploading the JSON to PHP it is saved as "canu0027t get there" without the "\" in the MySQL DB.

So how can I properly label/mark/identify this JSON string as UTF-8 format in Android so that it is saved correctly?

Solved

You have to escape (e.g. mysql_real_escape_string()) the json string in your php code before saving it into the database. Your Android code is just correct.


This is the solution:

StringEntity se = new StringEntity(jObjEnvio.toString(), HTTP.UTF_8);

If this dont work do clean and fix the project.


Sunday, August 19, 2018

Custom Callout Dialogue for map annotation

I don't know much about the MK_MapView, but I inherited a project that needs to have a custom dialogue popup when the user taps an annotation on the map.

Currently the dialogue is a custom MKAnnotation that uses the title, subtitle and detail disclosure. I need a dialogue that essentially looks exactly the same but with one additional line added to it under the subtitle.

I have yet to find a good guide or steps to crate a custom callout dialogue.

I found this Custom MKAnnotation callout bubble with button but when i do the steps provided in the didSelet method, i get a display of both the custom popup and the original, displayed on top of each other.

How can i get what i need?

Thanks

Solved

Where you create your MKAnnotationView in (If you don´t have implement this methods, is part of MKMapViewDelegate) copy like that, near that (- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view):

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
 {
 static NSString *reuseIdentifier = @"reuseIdentifier";
 MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
annotationView.canShowCallout = NO;



 return annotationView;
 }

Saturday, August 18, 2018

Setting Timestamps on files/directories is extremely slow

I'm working on a project, which requires to copy a lot of files and directories, while preserving their original timestamps. So I need to make many calls to the target's SetCreationTime(), SetLastWriteTime() and SetLastAccessTime() methods in order to copy the original values from source to target. As the screenshot below shows, these simple operations take up to 42% of the total computation time.

performance analysis

Since this is limiting my whole application's performance tremendously, I'd like to speed things up. I assume, that each of these calls requires to open and close a new stream to the file/directory. If that's the reason, I'd like to leave this stream open until I finished writing all attributes. How do I accomplish this? I guess this would require the use of some P/Invoke.

Update:

I followed Lukas' advice to use the WinAPI method CreateFile(..) with the FILE_WRITE_ATTRIBUTES. In order to P/Invoke the mentioned method I created following wrapper:

public class Win32ApiWrapper
{
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern SafeFileHandle CreateFile(string lpFileName,
                                                    [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
                                                    [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
                                                    IntPtr lpSecurityAttributes, 
                                                    [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
                                                    [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
                                                    IntPtr hTemplateFile);

    public static SafeFileHandle CreateFileGetHandle(string path, int fileAttributes)
    {
        return CreateFile(path,
                (FileAccess)(EFileAccess.FILE_WRITE_ATTRIBUTES | EFileAccess.FILE_WRITE_DATA),
                0,
                IntPtr.Zero,
                FileMode.Create,
                (FileAttributes)fileAttributes,
                IntPtr.Zero);
        }
}

The enums I used can be found here.This allowed me to do all all things with only opening the file once: Create the file, apply all attributes, set the timestamps and copy the actual content from the original file.

FileInfo targetFile;
int fileAttributes;
IDictionary timeStamps; 

using (var hFile = Win32ApiWrapper.CreateFileGetHandle(targetFile.FullName, attributeFlags))
using (var targetStream = new FileStream(hFile, FileAccess.Write))
{
    // copy file
    Win32ApiWrapper.SetFileTime(hFile, timeStamps);
}

Was it worth the effort? YES. It reduced computation time by ~40% from 86s to 51s.

Results before optimization:

before

Results after optimization:

after

Solved

I'm not a C# programmer and I don't know how those System.IO.FileSystemInfo methods are implemented. But I've made a few tests with the WIN32 API function SetFileTime(..) which will be called by C# at some point.

Here is the code snippet of my benchmark-loop:

#define NO_OF_ITERATIONS   100000

int iteration;
DWORD tStart;
SYSTEMTIME tSys;
FILETIME tFile;
HANDLE hFile;
DWORD tEllapsed;


iteration = NO_OF_ITERATIONS;
GetLocalTime(&tSys);
tStart = GetTickCount();
while (iteration)
{
   tSys.wYear++;
   if (tSys.wYear > 2020)
   {
      tSys.wYear = 2000;
   }

   SystemTimeToFileTime(&tSys, &tFile);
   hFile = CreateFile("test.dat",
                      GENERIC_WRITE,   // FILE_WRITE_ATTRIBUTES
                      0,
                      NULL,
                      OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL,
                      NULL);
   if (hFile == INVALID_HANDLE_VALUE)
   {
      printf("CreateFile(..) failed (error: %d)\n", GetLastError());
      break;
   }

   SetFileTime(hFile, &tFile, &tFile, &tFile);

   CloseHandle(hFile);
   iteration--;
}
tEllapsed = GetTickCount() - tStart;

I've seen that the expensive part of setting the file times is the opening/closing of the file. About 60% of the time is used to open the file and about 40% to close it (which needs to flush the modifications to disc). The above loop took about 9s for 10000 iterations.

A little research showed that calling CreateFile(..) with FILE_WRITE_ATTRIBUTES (instead of GENERIC_WRITE) is sufficient to change the time attributes of a file.

This modification speed things up significantly! Now the same loop finishes within 2s for 10000 iterations. Since the number of iterations is quite small I've made a second run with 100000 iterations to get a more reliable time measurement:

  • FILE_WRITE_ATTRIBUTES: 5 runs with 100000 iterations: 12.7-13.2s
  • GENERIC_WRITE: 5 runs with 100000 iterations: 63.2-72.5s

Based on the above numbers my guess is that the C# methods use the wrong access mode when opening the file to change to file time. Or some other C# behavior slows things down...

So maybe a solution to your speed issue is to implement a DLL which exports a C function which changes the file times using SetFileTime(..)? Or maybe you can even import the functions CreateFile(..), SetFileTime(..) and CloseHandle(..) directly to avoid calling the C# methods?

Good luck!