Thursday, April 17, 2014

Eclipse ADT Update

Quick info:


Eclipse ADT plugin asks for an update from time to time. If you get weird errors for ADT plugin update, i got some workaround for you.

In Eclipse, Go to Help menu:
Help > Install New Software
Then Add new entry or choose the name for https://dl-ssl.google.com/android/eclipse/ (with slash at the end)
Select the updates to install and then uncheck "Contact all update sites during install to find required software".


Friday, April 4, 2014

Interact with Azure Active Directory from Ruby on Rails


Ruby on Rails is a popular framework to build websites. You could follow the guidelines here to get started: http://guides.rubyonrails.org/. It gives templates to start a simple blog or a webapi, but it is somewhat forcing to Rail way. I mentioned all that as you may try it first time, you may not like the issues with dependencies. Here, i assume you know how to run simple website and update a controller. I will just give short example to use existing oauth library to access to Azure Active Directory. 

We will use Oauth2 library. Here is the github repo for that: https://github.com/intridea/oauth2
You should include require statement at the top of the controller. 

How does it work

WebApp needs to get the authorization code after the user enters the credential and page redirects with authorization code in query parameters. 

require 'oauth2'
class WelcomeController < ApplicationController # You need to configure a tenant at Azure Active Directory(AAD) to register web app and web service app # You will need two entries for these app at the AAD portal # You will put clientid and clientsecret for your web app here # ResourceId is the webservice that you registered # RedirectUri is registered for your web app CLIENT_ID = 'b6a42...' CLIENT_SECRET = 'TSbx..' AUTHORITY = 'https://login.windows.net/' AUTHORIZE_URL = "/yourtenant.onmicrosoft.com/oauth2/authorize" TOKEN_URL = "/yourtenant.onmicrosoft.com/oauth2/token" RESOURCE_ID = 'https://yourtenant.onmicrosoft.com/AllHandsTry' #ResourceId or ResourceURI that you registered at Azure Active Directory REDIRECT_URI = 'http://localhost:3000/welcome/callback' # landing page to redirect for authorization url, if token does not exist def index update_token if session['access_token'] # show main page and use token redirect_to welcome_use_token_path else # start authorization client = get_client a = client.auth_code.authorize_url(:client_id => CLIENT_ID, :resource => RESOURCE_ID, :redirect_uri => REDIRECT_URI) redirect_to(a) end end   # redirect will return to this page. You need to configure your redirectUri like: http://yoursite.com/callback def callback begin @code = params[:code] client = get_client # post token to mobile service api #token = client.auth_code.get_token(CGI.escape(@code), :redirect_uri => REDIRECT_URI) # id_token token.params["id_token"] #multi resource token token.params["resource"] token = client.auth_code.get_token(@code, :redirect_uri => REDIRECT_URI, ) session['access_token'] = token.token session['refresh_token'] = token.refresh_token session['expire_at'] = token.expire_at session['instance_url'] = token.params['instance_url'] redirect '/' rescue => exception output = '<html><body><p>' output += "Exception: #{exception.message}<br/>"+exception.backtrace.join('<br/>') output += '</p></body></html>' end end # if you want to update tokens def update_token puts "update token inside" token = session['access_token'] refresh_token = session['refresh_token'] expire_at = session['expire_at'] @access_token = OAuth2::AccessToken.from_hash(get_client, { :access_token => token, :refresh_token => refresh_token, :expire_at => expire_at, :header_format => 'Bearer %s' } ) if @access_token.expired? puts "refresh token" @access_token = @access_token.refresh!; session['access_token'] = @access_token.token session['refresh_token'] = @access_token.refresh_token session['expire_at'] = @access_token.expire_at session['instance_url'] = @access_token.params['instance_url'] end end # send request to a webservice to use a token def use_token # we got the token and now it will posted to the web service in the header # you can specify additional headers as well # token is included by default update_token conn = Faraday.new(:url => 'https://yoursite.azurewebsites.net/') do |faraday| faraday.request :url_encoded # form-encode POST params faraday.response :logger # log requests to STDOUT faraday.adapter Faraday.default_adapter # make requests with Net::HTTP end response = conn.get do |req| req.url '/api/WorkItem' req.headers['Content-Type'] = 'application/json' req.headers['Authorization'] = 'Bearer '+@access_token.token end @out = response.body end def get_client client = OAuth2::Client.new(CLIENT_ID, CLIENT_SECRET, :site => AUTHORITY, :authorize_url => AUTHORIZE_URL, :token_url => TOKEN_URL ) client end end

You could plug in your clientId, authority, resourceid after you configure your app at Azure Active Directory portal. I will try to extend this later. You can access the gist from here: https://gist.github.com/omercs/9918845

Azure Active Directory Library For Android



Azure Active Directory Library for Android

We have finally announced the Azure Active Directory(AAD) features at Build conference. It was exciting to hear about AAD at Keynotes.

This is not an official blog post, but I will show some details about the Android Library and app setup.  You can easily libraries access from https://github.com/MSOpenTech/azure-activedirectory-library-for-android and https://github.com/MSOpenTech/azure-activedirectory-library-for-ios

Prerequisites for Android development:



  • Install Git source control
  • Install Android SDK: https://developer.android.com/sdk/index.html?hl=sk
  • Make sure you can run some samples under the sdk/samples
  • Update SDKs and install SDK 15-19

  • It supports maven based installation, but you need to setup maven sdk deployer to actually do anything with latest Android SDKs since maven repos don't have the latest Android SDKs. You could skip Maven based installation and pull the dependent libraries directly. You could put them under the adal/libs folder.


    • Android-Support-v4: Fix project properties and it will be added
    • gson library: https://code.google.com/p/google-gson/downloads/list

    If you insist to setup maven environment, I will quickly walk through the details for your environment setup.

    Install Maven 3.1.1: http://maven.apache.org/download.cgi

    Maven helps to manage dependencies and build your project. Our sample app will be compiled with Eclipse ADT, so i am not forcing you to make maven based app.

    You need to put the latest android SDKs into local maven repo. You could use these commands to install SDK19 and support library:
    git clone https://github.com/mosabua/maven-android-sdk-deployer.git
    cd maven-android-sdk-deployer\platforms\android-19
    mvn clean install
    cd ..\..\extras\compatibility-v4
    mvn clean install
    You can clone and install from cmd line:
    git clone https://github.com/MSOpenTech/azure-activedirectory-library-for-android.git
    cd azure-activedirectory-library-for-android
    mvn clean install


    How to Add Android Library to your Project

    1. Add reference to your project as Android library. Please check here:http://developer.android.com/tools/projects/projects-eclipse.html
    2. Add project dependency for debugging in your project settings
    3. Update your project's AndroidManifest.xml file to include the authentication activity:
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      <application
            android:allowBackup="true"
            android:debuggable="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
    
            <activity
                android:name="com.microsoft.adal.AuthenticationActivity"
                android:label="@string/title_login_hello_app" >
            </activity>
      ....
      <application/>

    Setup Native Client App at Azure Active Directory

    1.  Register your WEBAPI service app at Azure Active Directory(AAD),https://manage.windowsazure.com
      1. You need APP ID URI parameter to get token
    2. Register your client native app at AAD
      1. You need clientId and redirectUri parameters
      2. Select webapis in the list and give permission to previously registered(Step5) WebAPI

    Go to Azure portal:

    Create Directory entry if you don't have at Azure portal


     Click Active Directory to Create an App:
    Add an explication that you are developing
    Follow the wizard to setup the app.


    Define Native Client app to create Android app entry
    Redirect Uri needs to be unique. It is better to link to your domain. If you don't have, you can use your azure active directory address like "yourtenant.onmicrosoft.com".
    Define unique RedirecUri entry
    Configure the entry for permissions

    Update your app for App settings

    • Resource is required, Clientid is required. PromptBehavior helps to ask for credentials to skip cache and cookie. Callback ill be called after authorization code is exchanged for a token. It will have an object of AuthenticationResult, which has accesstoken, date expired, and idtoken info.
      1. You can always call acquireToken to handle caching, token refresh and credential prompt if required. Your callback implementation should handle the user cancellation for AuthenticationActivity. ADAL will return a cancellation error, if user cancels the credential entry.
    • Authority Url and ADFS

      ADFS is not recognized as production STS, so you need to turn of instance discovery and pass false for validation at AuthenticationContext constructor.
      Authority url needs to be in the form of STS instance and tenant name: https://login.windows.net/yourtenant.onmicrosoft.com

    Usage of AuthenticationContext

    1. Create an instance of AuthenticationContext at your main Activity. You can look at sample projects that is used for testing.
      mContext = new AuthenticationContext(MainActivity.this, authority, true); // This will use SharedPreferences as default cache
    
    mContext is a field in your activity. Copy this code block to handle the end of AuthenticationActivity after user enters credentials and receives authorization code:
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
         if (mContext != null) {
             mContext.onActivityResult(requestCode, resultCode, data);
         }
     }
    To ask for a token, you need to define a callback:
    private AuthenticationCallback<AuthenticationResult> callback = new AuthenticationCallback<AuthenticationResult>() {
    
            @Override
            public void onError(Exception exc) {
                if (exc instanceof AuthenticationException) {
                    textViewStatus.setText("Cancelled");
                    Log.d(TAG, "Cancelled");
                } else {
                    textViewStatus.setText("Authentication error:" + exc.getMessage());
                    Log.d(TAG, "Authentication error:" + exc.getMessage());
                }
            }
    
            @Override
            public void onSuccess(AuthenticationResult result) {
                mResult = result;
    
                if (result == null || result.getAccessToken() == null
                        || result.getAccessToken().isEmpty()) {
                    textViewStatus.setText("Token is empty");
                    Log.d(TAG, "Token is empty");
                } else {
                    // request is successful
                    Log.d(TAG, "Status:" + result.getStatus() + " Expired:"
                            + result.getExpiresOn().toString());
                    textViewStatus.setText(PASSED);
                }
            }
        };
    Ask for a token:
     mContext.acquireToken(MainActivity.this, resource, clientId, redirect, userid, PromptBehavior.Auto, "",
                    callback);
    • Querying cache items

      ADAL provides Default cache in SharedPrefrecens with some simple cache query fucntions. You can get the current cache from AuthenticationContext with:
       ITokenCacheStore cache = mContext.getCache();
      
      You can also provide your cache implementation, if you want to customize it.
      mContext = new AuthenticationContext(MainActivity.this, authority, true, yourCache);
      

      Logger

      ADAL provides simple callback logger. You can set your callback for logging.
      Logger.getInstance().setExternalLogger(new ILogger() {
          @Override
          public void Log(String tag, String message, String additionalMessage, LogLevel level, ADALError errorCode) {
          ...
          }
      }
      // you can manage min log level as well
      Logger.getInstance().setLogLevel(Logger.LogLevel.Verbose);

    Multi Resource Refresh Token

    You may have several Web API services that you use in your app. When you get a token for resource1, you could use refresh token from resource1 to get access token for resource2. This will work if you use same authority, clientid and userid in the second call. Internal cache will help to reuse multi resource refresh tokens.
    mContext.acquireToken(MainActivity.this, resource1, clientId, redirect, userid, PromptBehavior.Auto, "",
                    callback);
    mContext.acquireToken(MainActivity.this, resource2, clientId, redirect, userid, PromptBehavior.Auto, "",
                    callback);
    Second call here will not display prompt screen. It will only send refresh token web request.

    Happy coding!
    ------------------------The END------------------------

    Monday, October 21, 2013

    WebAPI project secured by Windows Azure Active Directory in Visual Studio 2013


    I really liked the recent Azure Active Directory(AAD) integration on Visual Studio 2013. It enables to add AAD authentication to your projects. Vittorio talked about that in his post. I tried that and added some screenshots for you to show the process for WebAPI publishing at Azure Websites.

    First step is to get Visual Studio 2013: You can follow the links at http://www.microsoft.com/visualstudio/eng/downloads to get the initial version. I am assuming you want to create a webapi project for your mobile platform.

    Figure: Add project

    After clicking ok button, you will see new button there in the web projects. When you click "change authentication" button, you can set the organizational account at active directory that you created at Azure AD. It is very easy to add Azure Active Directory, if you have azure subscriptions. You can look at this tutorial to see about adding Active Directory at Azure.

    Figure: Project list

    Once you clicked the "change authentication" button, you need to enter your admin user at Azure Active Directory(AAD). This is not your live account. It needs to be your admin user at AAD. If everything looks good, Visual Studio 2013 will create your WebAPI project and add entries to Web.config file. It is using Owin, so you will see related references added to your project. You will also see startup file inside App_Start folder.

    Figure: Login screen to enter AAD admin user credentials

    Figure: Startup file for configuration


    You can publish this project to Azure Website easily. You can use default ValuesController to test the process and later add your implementation for different controllers. Default endpoint will ask for token at "/api/values/". If you remove "authorize" attribute form controller, it will not check Tokens in the request. With simple authorize attribute, you will have all the logic to check tokens inside the coming requests.

    To create Azure website, you can go to Azure portal and click wizard to create the website:
    Figure: Azure website

    After your website is created, you can get the publish profile as shown below:
    Figure: you can click link to get the profile

    You can publish the webAPI project by right clicking the publish button at your project You need to set correct publish settings, if you don't want your config to be changed at publication. 
    Figure: Publish settings

    You deployed a sample app to your Azure Active Directory and it is ready to be used by your AAD users. You will see one entry in the Azure Active Directory for your app. ClientID, ClientSecret and RedirectUri and permissions are important things to configure for your app. I will talk about those configuration in next posts and how to use WebAPI in different platforms. Stay tune!



    Saturday, June 23, 2012

    Metaprogramming in Ruby

    Ruby is a dynamically typed language. You can define methods and classes at run time. Ruby has several metaprogramming styles.

    One way is to use "define_method":

    #defining new class
    c = Class.new
    c.class_eval do
        define_method :hi do
            puts "hello say hi"
        end
    
        define_method :get_price  do |productname, location|
          puts "4$ for product #{productname} #{location}"
        end
    
        #method with default location
        define_method :get_price_2  do |productname, defaultlocation="rr"|
          puts "4$ for product #{productname} #{defaultlocation}"
        end
    
    
    end
    
    c.new.hi
    c.new.get_price("bike","charlotte")
    c.new.get_price_2("bike" )
    c.new.get_price_2("bike","not rr" )
    Prints:
    hello say hi
    4$ for product bike charlotte
    4$ for product bike rr
    4$ for product bike not rr

    Inside this code block, we are creating a new class with three methods. First method is not taking any parameter. Second method is  taking two parameters. Third method is taking two parameters and last parameter is with the default value.

    Another method for metaprogramming is using eval keyword. You can compile any string into a code. That is scary and somewhat crazy to me. It might be good for Artificial Intelligence projects, but not much useful for production application that you need to maintain and troubleshoot.


    class MyClass
       eval %{def hi
                  puts "Eval code string at runtime hello world"
              end
            }
    
    end
    
    d = MyClass.new
    d.hi
    Prints:
    Eval code string at runtime hello world
    
    
    This code block is taking a string and running that. You can do similar code eval syntax in javascript and php as well.

    You can also define classes inside the loop and use that class outside or inside the loop.


    2.times do
      class Classtimes
        puts "hello world from Class time objectid #{self.object_id} classid #{self.class.object_id} "
      end
      class Classtime2
        def printit
          puts "hello world from Classtime2 printit objectid #{self.object_id} classid #{self.class.object_id} "
        end
      end
      Classtime2.new.printit
    end

    
    
    Inside this code block, first class uses same object to print. Second class will create new objects for each iteration, but class will be defined once. Here is the output:
    
    
    hey world from Class time objectid 18939288 classid 15445296 
    hey world from Classtime2 printit objectid 18939156 classid 18939192 
    hey world from Class time objectid 18939288 classid 15445296 
    hey world from Classtime2 printit objectid 18938988 classid 18939192 
    
    If you define the same class again outside of this loop, you may be wondering about the outcome. Ruby lets you extend the class,so it will use the same class to add method. It is similar to using partial keyword in C#, but you can have dynamic extensions with Ruby.
    
    
    #right after 2.times block code
    class Classtime2
      def printitagain
        puts "hey world from Classtime2 printitagain objectid #{self.object_id} classid #{self.class.object_id} "
      end
    end
    Classtime2.new.printitagain
    Output:
    hey world from Classtime2 printitagain objectid 18938904 classid 18939192


    puts "you can look at instance methods and variables easily"
    p MyClass.new.instance_variables
    p MyClass.instance_methods(false)
    p Classtime2.instance_methods(false)
    
    
    Output:
    you can look at instance methods and variables easily
    []
    [:hi]
    [:printit, :printitagain]
    
    
    
    
    
    
    TODO for this subject:
    Module extension
    class << self
    extending methods for single object
    
    
    
    

    Monday, May 21, 2012

    C# 'var' keyword versus explicitly defined variables

     If you explicitly define your variable like this:

    
    
    
    
    
    
    List<MySuperEngine> lstString = new List<MySuperEngine>;
    
    

    Resharper may make a suggestion to use var keyword. It helps for typing and readiblity of code. If it is not ambigous to use it, you can replace first part with var.
    
    
    
    
    
    
    var lstString = new List<MySuperEngine>;
    
    
    
    
    
    


    I know the type of the object, so it is obvious what we are referring to with "var" keyword. It is useful if the type name is too long to type it like

    MyanotherClassWithNameSpace.ClassA obj = new MyanotherClassWithNameSpace.ClassA();


    "var" keyword is not same as "dynamic" keyword. "var" is only place holder and it is for your convenience. It saves extra typing. You will have same IL code as explicit definition.

    
    
    
    

    Friday, May 18, 2012

    Meetup for Azure and MVC4



    I like the meetup.com and created one group for Azure and MVC
    http://www.meetup.com/Windows-Azure-RTP-Ninjas/

    We will have first meeting on May,30th at 7pm near my office somewhere. I need to find a good room for that.


    Monday, May 14, 2012

    File Upload Asp.net Mvc3.0


    You need to add file html element and set the form type to multipart to upload files. For example, we are sending one file to UserFileController class and upload method with Post method. When user submits ok, it will upload file directly.


    @using (Html.BeginForm("Upload", "UserFile", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        <input type="file" name="file" />
        <input type="submit" value="OK" />
    }
    
    You can check request files to see their content.
    
    
    public class UserFileController : Controller
    {
        // Index of files
        public ActionResult Index()
        {
            return View();
        }
    
        
    
       // render the page
     public ActionResult Upload()
        {
         return View();
        }
        // Upload
        [HttpPost]
        public ActionResult Upload(HttpPostedFileBase file)
        {
            // You can verify that the user selected a file
            if (file != null && file.ContentLength > 0) 
            {
                // Filename is provided to you
                var fileName = Path.GetFileName(file.FileName);
                // you can simply save file to some folder with updated name
                fileName += Guid.NewGuid().ToString();
                //you can record some information if you want...
    var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName); file.SaveAs(path); } // redirect back to the index action to show the form once again return RedirectToAction("Index"); } }
    
    If you have multiple files, you can go through collection of files in the request stream to save them.


    // Upload
        [HttpPost]
        public ActionResult Upload(int nothingreallyhereNeeded)
        {


    try
                    {
                        HttpFileCollectionBase hfc = Request.Files;
                        
    
                        if (hfc.Count > 0)
                        {
                            String h  = hfc.AllKeys.FirstOrDefault();
                            //multiple files
                            if (hfc[h].ContentLength > 0)
                            {
                                 //we are recording info about file
                                CustomerFileRecord fileRecord = new CustomerFileRecord();
                                fileRecord.ReadStart = DateTime.UtcNow;
                       
                                Stream str = hfc[h].InputStream;
                                int fsize = 0;
                                if (str.Length > 0)
                                {
                                    //just checking stream length
                                    fileRecord.FileSize = (int)str.Length / 1000;
                                }
                                fileRecord.CreatedOn = DateTime.UtcNow;
                                fileRecord.Name = hfc[h].FileName;
                                fileRecord.FullName = DataFolder + fileRecord.Name;
                                hfc[h].SaveAs(DataFolder  + fileRecord.Name);
                                 
                                db.CustomerFileRecords.AddObject(fileRecord);
                                db.SaveChanges();
    
                                 
                            //do some file processing if you want.. or put into queue to process later.
                            
    
                                
    
                              return RedirectToAction("Index");  
    } else { msg = "Empty file"; } } else { msg = "File is not attached"; } } catch (Exception ex) { logger.ErrorException("Upload data file"+ex.Message,ex); msg += "Error in processing data file: "+ex.Message; }
    ViewBag.Message = msg;
    return View();
    }

    Friday, May 11, 2012

    Wednesday, May 2, 2012

    Integration Service foreach file loop

    Most simple integration systems use files with various formats to move data. Client drops a file to a folder for processing and your system takes that to update account balance, send email to bunch of people or send work orders. When you are working with files, you can use integration service's drag and drop features to create an integration package. BI development studio is very good for designing control flow items, data flow items and overall database integrations.

    I was almost to give 5 star rating to script task feature in there, but it is hard to debug and work with. It is a good flexiblity to add your C# code inside the package you are building. It must be hard to maintain all those script code and then debug production problems.

    Here are the steps to make a package for monitoring a directory and then importing data from each file.

    Step1: Create a new Integration Services Project from SQL Server business intelligence development studio


    Step2: Drag and drop Foreach Loop Container to Control flow

    Step3: Right click in the control flow screen and select variables option to define the following variables.



    • FileRecordId: to use as a reference to your file record in the file reference table, 
    • ImportFileName: name of the file that we will record into table
    • ImportFileShortName: only filename
    • ImportFileSize: Script Task will update this variable for file size.
    • ImportFolder: to define folder for our Foreach loop


    ImportFolder has predefined value and we will not change that in this demo. Other values will change

    Step4:We will be processing each file in our "ImportFolder" directory and recording file info. We will use SqlTask to insert queries, Script Task to get file info and BulkInsert to add records. Now, we will drag and drop SQL Task, Script Task,  another Sql Task, Bulk Insert Task, and final File System Task. You should see this screen after dropping all those.


    Step5:Now we need to define our directory folder for "FOREACH Loop container". Set foreach container enumerator to File enumerator and then click expressions. You can set property column to "Directory" from dropdown and set value to @[User::ImportFolder]


    This will set the directory to our import folder variable.

    Step6: We need to set read only and read write variables for script editor.
    ReadOnlyVariables: User::ImportFileName
    ReadWriteVariables:User::ImportFileShortName,User::ImportFileSize



    You need to click "edit script" button to open script editor. I put file operations into script task to use script feature.

    You can call variables with Dts.Variables["ImportFileName"].Value and use the same syntax to set the value. You should specify these variable in the readonly and readwrite variable list.

     
     public void Main()
            {
    
                Dts.Log("start script task", 999, null);
                //get file size
                string filepath = (string)Dts.Variables["ImportFileName"].Value;
                if (File.Exists(filepath))
                {
                    Dts.Log("File exists", 999, null);
                    //get size
                    FileInfo flatfileinfo = new FileInfo(filepath);
    
                    Int32 filesize = (Int32)(flatfileinfo.Length/1000);
                    Dts.Variables["ImportFileShortName"].Value = flatfileinfo.Name;
    
                    //write this size
                    Dts.Variables["ImportFileSize"].Value = filesize;
                    Dts.TaskResult = (int)ScriptResults.Success;
                    Dts.Log("finished script task", 999, null);
                    return;
                }
                 
                Dts.TaskResult = (int)ScriptResults.Failure;
                Dts.Log("failed script task", 999, null);
            }
    
    Step7: We will use SQL task to insert file info to the filerecord table.




    Ole Db is using Question mark to identify input variables. You need to map variables in parameter mapping screen.

    Query:
     INSERT INTO [dbo].[CustomerFileRecords]
               ([CreatedOn]
               ,[FileSize]
               ,[Name]
               ,[TotalLines]
               ,[ReadStart]
               ,[ReadEnd]
               ,[ImportedRecords]
               ,[ErrRecords]
               ,[Comment]
               ,FullName)
         VALUES
               (getutcdate()
               ,?
               ,?
               ,0
               ,getutcdate()
               ,null
               ,null
               ,null
               ,'add file info'
               ,?)
    
    declare @i int
    set @i =  scope_identity();
    
    select  @i  as FileId
    
    
    This simple query inserts a record into File record table about the file size, file name and file path. You are taking these information from Script Task and assigning to variables. Query task is using same variables to create a record. 
    
    
    Step8: Next task is to call bulk insert to move data into temporary table. We need to define file source. You can add flat file source to use in bulk insert operation. Right click then select new connection. If you select flat file source, this screen will pop up.


    File name is not important, because we will map to our variable.

    Click flat file properties in the control flow screen and set connection string to "@[User::ImportFileName]"


    Drag and drop bulk insert operation. You need to set source connection to your flat file source.

    Set connections to your database and also set the destination table. Destination table should have same columns as your data file if you are importing data with default settings.


    Step9: Next step is to delete the data file after processing. We will add File System Task to delete a file.

    Source variable "User::ImportFileName" was populated from Foreach container.


    This loop will run for each file in the specified folder and execute script and sql queries. We used sql task, file system task, Bulk insert, Script task and iterator.

    You can use other tasks to add more features.