mdisoft : c#ding with passion

RSS

Creating a Data Access Layer with Linq-to-Sql in a Separate Project

In our current project we had a need to separate a DAL from web logic and REST API, while it was not really a problem to move files from one project to another, matching the connection string and places where it saves was not that easy after all. Thankfully, we came to across to that article that perfectly explains the problem and the solution.

Originally written by Graham O’Neale in his blog.

Did you know that by default LINQ to SQL defines your connection string in more than one place if you define your LINQ to SQL classes out from a web app, such as a data access layer class library?

  1. Under “Application Settings” stored as Settings.settings and compiled in with your code rendering it unchangeable without recompilation and making it very easy to be inspected upon via reflection.
  2. Stored in Web.config / App.config as a reference copy from “Application Settings” in making it very disconcerting as to the true location it is picked up from.
  3. Hard coded in the “.dbml” file of the <Connection /> node as clear text.


Three places?! For standalone web applications it’s not so bad, as it turns out it is still stored in the Web.config and hard coded to the .dbml file, but the connection string is changeable on the fly and it does not store any strings which are baked in.

However if you wish to setup a layered n-tier architecture with your LINQ to SQL classes residing in a separate project, you will suffer the compilation “gotcha”.  Point 1 was a particular problem for me as I needed to update the connection string after compilation with an NAnt build script for deployment to a testing server.  This obviously wasn’t acceptable, as it did not honour changes easily between different database configuration across multiple environments (dev, test, production) so I needed another solution.

Thankfully there was one, and it will shorten that list down (you will still be stuck with a local “.dbml” conn. string copy which appears to pose no deployment implication as it simply tells the LINQ to SQL designer which DB you are working with, which is good).

Remember the below instructions are if you have a separate project holding your LINQ to SQL classes or you your connection string is being compiled into application settings (potentially anything but a Web application?) What we want to do is first turn off application wide settings effectively freeing it from LINQ to SQL: -

  1. Open up the LINQ to SQL designer, and open the Properties tab of the designer (the schema itself), expand Connection and set Application Settings to False. Save.  Don’t you feel better already?
  2. Close that down and open up your DataContext designer file (dbml_name.designer.cs) and alter the DataContext constructor.  You will immediately notice how your connection string decided to jump in here as you turned off application wide settings.  So the part to focus on here is altering the base() inheritor. Renaming “MyConnString” below to suit your own. I also noticed a DatabaseAttribute on the class which I don’t think plays a big part and has any implications on the connection settings. You will also need a reference to System.Configuration:
    1. public dbDataContext() :
    2.      base(ConfigurationManager.ConnectionStrings[“MyConnString”].ConnectionString, mappingSource)
  3. Open the App.config or Web.config featured in the project where your LINQ to SQL classes reside, and rename the connection string to what you defined as “MyConnString“.
  4. You now must Cut the entire <connectionStrings /> entry with name change and Paste it into either the App.config or Web.config of the application which is to access the data, such as a web application, Silverlight, WPF, WCF etc.  It is important that you alter the configuration file of the calling application which is to access the data, as the ConfigurationManager defined in your LINQ to SQL classes will look for the .config file from where the calling application is executing from, no matter where your LINQ to SQL classes have been defined.  As you can see, it works a little differently from before.
  5. Now Right Click and open the Properties on your DAL or project containing your LINQ to SQL classes and remove the connection string “Application Setting” reference on the Settings tab.
  6. Rebuild.  You’re all done, now just do a Find in Files check for perhaps your database name that you know was featured in the connection string to check for any stragglers, there shouldn’t be any.


Now you can alter your configuration of App.config / Web.config at your discretion without fear that the connection string is embedded somewhere nasty and won’t be picked up!

That’s it. Happy c#ding!

Apple Push Notifications (APNS) with .Net C# and IIS

After 2 days of researching and trying I was finally able to configure our IIS (7.5) server to send Push Notifications to our iPhone App. As many developers have previously pointed out, the hardest part actually is to receive a right certificate from Apple Provisioning Portal. I hope this article can help you to get your APNS up and running within 10 minutes or less.

 

Step 1: Apply and receive a certificate from Apple, generate a new provisioning profile and have it installed and referenced in your project settings.

http://arashnorouzi.wordpress.com/2011/04/01/sending-apple-push-notifications-in-asp-net-%E2%80%93-part-2-generating-apns-certificates/

 

Step 2 : Export an installed certificate from your keychain to generate .p12 personal certificate that we need to save on our IIS server.

After you’ve created the appropriate Push Notification Certificate in iPhone Developer Program Portal you should have downloaded a file named something like apn_developer_identity.cer. If you have not done so already, you should open/import this file into Keychain, into your login section.

Finally, if you filter Keychain to show your login container’s Certificates, you should see your Certificate listed. Expand the certificate, and there should be a Key underneath/attached to it.

Right Click or Ctrl+Click on the appropriate Certificate and choose Export. Keychain will ask you to choose a password to export to. Pick one and remember it. You should end up with a .p12 file. You will need this file and the password you picked to use the Notification and Feedback Libraries here.

 

Step 3 : Enable a push notification in your iOS solution, add this code to your AppDelegate

 

#import “ApplePushNotificationAppDelegate.h”

#import “ApplePushNotificationViewController.h”

@implementation ApplePushNotificationAppDelegate

@synthesize window;

@synthesize viewController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

    [window addSubview:viewController.view];

    [window makeKeyAndVisible];

    NSLog(@”Registering for push notifications…”);    

    [[UIApplication sharedApplication] 

        registerForRemoteNotificationTypes:

        (UIRemoteNotificationTypeAlert | 

         UIRemoteNotificationTypeBadge | 

         UIRemoteNotificationTypeSound)];

}

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { 

    NSString *str = [NSString 

        stringWithFormat:@”Device Token=%@”,deviceToken];

    NSLog(str);

}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err { 

    NSString *str = [NSString stringWithFormat: @”Error: %@”, err];

    NSLog(str);    

}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

    for (id key in userInfo) {

        NSLog(@”key: %@, value: %@”, key, [userInfo objectForKey:key]);

    }    

}

- (void)dealloc {

    [viewController release];

    [window release];

    [super dealloc];

}

@end

 

Step 4:  Download APNS-CSharp binaries from https://github.com/Redth/APNS-Sharp and reference it in your solution.  It’s really easy to use and it takes 3 rows to actually send your notifications.

Sample Code

string p12FileName = “C:\apple_ios_certificate.p12”; // change this to reflect your own certificate

string p12Password = “”; // change this

bool sandBox = true;

int numConnections = 1; // you can change the number of connections here

var notificationService = new NotificationService(sandBox, p12FileName, p12Password, numConnections);

var deviceToken = “”; // put in your device token here

var notification = new Notification(deviceToken);

notification.Payload.Alert.Body = “Some message”;

notification.Payload.Sound = “beep.wav”;

notification.Payload.Badge = 1;

if (notificationService.QueueNotification(notification)) {

    // queued the notification

} else {

    // failed to queue

}

// This ensures any queued notifications get sent befor the connections are closed

notificationService.Close();

notificationService.Dispose();

Here are some things to point out.

P12 file – the file that you got completing step#2,

password – a password that you specified during the export.

device token – a unique device id issued by Apple when application has a push notification feature enabled (see step 3). It makes sense to send it and save it in your database and to associate with an user account id.

 

Step 5: Here’s the juicy part – install .net solution on your web server. I have tested it only with our IIS 7.5. In some tutorials people are suggesting to register/add your p12 certificate to server via mmc panel. Others, are suggesting to open firewall ports 2195-2196. I have tried with and tried without. It worked fine without extra headache.

So the only thing you need to change in your DefaultAppPool Advanced settings  is the identity. It’s should be changed to LocalSystem.


And that’s it. Happy c#ding!  

Android: how to check if service is running?

There’re situations where you need to check if service is already running. And it’s pretty easy…

private boolean isServiceRunning() {

    ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE);

    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {

        if (“your.servicename”.equals(service.service.getClassName())) {                     return true;
        }
    }
    return false;
}

REST WCF and Basic Authentication

Creating a REST API using WCF is not that complicated and requires some basic knowledge of WCF and web.config. But figure out how the heck to configure your server/solution to accept basic authentication and check login and password against .Net Membership API is a pain in the ass. Fortunately, we’ve found an easy way out! Here’s what you gotta do:

1. Download WCF REST Starter Kit

http://aspnet.codeplex.com/releases/view/24644

From this solution you simply need Microsoft.ServiceModel.Web.dll to be referenced in your project.

2. Create a class called BasicAuthenticationInterceptor.cs

and copy&paste the following code:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.ServiceModel.Web;

using System.ServiceModel.Channels;

using System.ServiceModel.Web;

using System.Web.Security;

using System.Security.Principal;

using System.IdentityModel.Policy;

using System.ServiceModel;

using System.ServiceModel.Security;

using System.IdentityModel.Claims;

using System.Security.Cryptography;

using System.Net;

namespace [Your-namespace].RestService.BasicAuthen

{

    public class BasicAuthenticationInterceptor : RequestInterceptor

    {

        MembershipProvider provider;

        string realm;

        public BasicAuthenticationInterceptor(MembershipProvider provider, string realm)

            : base(false)

        {

            this.provider = provider;

            this.realm = realm;

        }

        protected string Realm

        {

            get { return realm; }

        }

        protected MembershipProvider Provider

        {

            get { return provider; }

        }

        public override void ProcessRequest(ref RequestContext requestContext)

        {

            string[] credentials = ExtractCredentials(requestContext.RequestMessage);

            if (credentials.Length > 0 && AuthenticateUser(credentials[0], credentials[1]))

            {

                InitializeSecurityContext(requestContext.RequestMessage, credentials[0]);

            }

            else

            {

                Message reply = Message.CreateMessage(MessageVersion.None, null);

                HttpResponseMessageProperty responseProperty = new HttpResponseMessageProperty() { StatusCode = HttpStatusCode.Unauthorized };

                responseProperty.Headers.Add(“WWW-Authenticate”,

                    String.Format(“Basic realm="{0}"”, Realm));

                reply.Properties[HttpResponseMessageProperty.Name] = responseProperty;

                requestContext.Reply(reply);

                requestContext = null;

            }

        }

        private bool AuthenticateUser(string username, string password)

        {

            if (Provider.ValidateUser(username, password))

            {

                return true;

            }

            return false;

        }

        private string[] ExtractCredentials(Message requestMessage)

        {

            HttpRequestMessageProperty request = (HttpRequestMessageProperty)requestMessage.Properties[HttpRequestMessageProperty.Name];

            string authHeader = request.Headers[“Authorization”];

            if (authHeader != null && authHeader.StartsWith(“Basic”))

            {

                string encodedUserPass = authHeader.Substring(6).Trim();

                Encoding encoding = Encoding.GetEncoding(“iso-8859-1”);

                string userPass = encoding.GetString(Convert.FromBase64String(encodedUserPass));

                int separator = userPass.IndexOf(‘:’);

                string[] credentials = new string[2];

                credentials[0] = userPass.Substring(0, separator);

                credentials[1] = userPass.Substring(separator + 1);

                return credentials;

            }

            return new string[] { };

        }

        private void InitializeSecurityContext(Message request, string username)

        {

            GenericPrincipal principal = new GenericPrincipal(new GenericIdentity(username), new string[] { });

            List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>();

            policies.Add(new PrincipalAuthorizationPolicy(principal));

            ServiceSecurityContext securityContext = new ServiceSecurityContext(policies.AsReadOnly());

            if (request.Properties.Security != null)

            {

                request.Properties.Security.ServiceSecurityContext = securityContext;

            }

            else

            {

                request.Properties.Security = new SecurityMessageProperty() { ServiceSecurityContext = securityContext };

            }

        }

        class PrincipalAuthorizationPolicy : IAuthorizationPolicy

        {

            string id = Guid.NewGuid().ToString();

            IPrincipal user;

            public PrincipalAuthorizationPolicy(IPrincipal user)

            {

                this.user = user;

            }

            public ClaimSet Issuer

            {

                get { return ClaimSet.System; }

            }

            public string Id

            {

                get { return this.id; }

            }

            public bool Evaluate(EvaluationContext evaluationContext, ref object state)

            {

                evaluationContext.AddClaimSet(this, new DefaultClaimSet(Claim.CreateNameClaim(user.Identity.Name)));

                evaluationContext.Properties[“Identities”] = new List<IIdentity>(new IIdentity[] { user.Identity });

                evaluationContext.Properties[“Principal”] = user;

                return true;

            }

        }

    }

}

3. Change Service.svc to the following:

<%@ ServiceHost Language=”C#” Debug=”true” Service=”Service” Factory=”AppServiceHostFactory” %>

using System;

using System.ServiceModel;

using System.ServiceModel.Activation;

using Microsoft.ServiceModel.Web;

using [your-solution-name].RestService.BasicAuthen;

class AppServiceHostFactory : ServiceHostFactory

{

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)

    {

        WebServiceHost2 result = new WebServiceHost2(serviceType, true, baseAddresses);

        result.Interceptors.Add(new BasicAuthenticationInterceptor(

            System.Web.Security.Membership.Provider, “[your-solution-name]”));

        return result;

    }

4. In your web.config file make sure to add standard sql membership provider reference as well as to have authentication mode- None

<authentication mode=”None”/>

<membership>

<providers>

<clear/>

<add name=”AspNetSqlMembershipProvider” type=”System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a” connectionStringName=”SkyferLive” enablePasswordRetrieval=”false” enablePasswordReset=”true” requiresQuestionAndAnswer=”false” requiresUniqueEmail=”false” passwordFormat=”Hashed” maxInvalidPasswordAttempts=”5” minRequiredPasswordLength=”6” minRequiredNonalphanumericCharacters=”0” passwordAttemptWindow=”10” passwordStrengthRegularExpression=”” applicationName=”/”/>

</providers>

</membership>

And at the end of your web.config make sure to add the following lines:

<system.serviceModel>

<serviceHostingEnvironment>

<baseAddressPrefixFilters>

<add prefix=”http://[your-pc-name]”/>

</baseAddressPrefixFilters>

</serviceHostingEnvironment>

</system.serviceModel>

That’s it. Happy c#ding!