C-sharp : Write a webjob in a website

Many a times in our web projects we require a process to run seperate from the main thread of website. We had a scenario once to host our asp.net website on Windows Azure. Different ways to do this.

The following file types are supported:

  • .cmd, .bat, .exe (using Windows cmd)
  • .ps1 (using PowerShell)
  • .sh (using Bash)
  • .php (using PHP)
  • .py (using Python)
  • .js (using Node.js)
  • .jar (using Java)

a- Write the code in global.asax startup method and run a timer. But that will run inside the main thread of website so it is not advisable to do that, as any sort of crash in either website or the timer thread will cause the pool to restart.

b- Write a Windows Service, this is a classic model if we have a Virtual machine in place, but if we have hosted our website as a Windows Azure Website, then this will not work.

c- If we host a Windows Azure website, which is a common scenario, Windows Azure provides an option to configure the webjob host from the control panel where we can assign different properties like Triggering [continous, manual] and scheduling.

The Windows Azure WebJobs SDK is a framework that simplifies the task of adding background processing to Windows Azure Web Sites.

Aside from the main project, create a new C# Console application.

First, we need to install “Azure WebJobs SDK”, we can add it through nuget module in our Visual Studio project.

To create a new WebJobs-enabled project, you can use the Console Application project template and enable WebJobs deployment as explained in the previous section. As an alternative, you can use the WebJobs new-project template:

  • Use the WebJobs new-project template for an independent WebJobCreate a project and configure it to deploy by itself as a WebJob, with no link to a web project. Use this option when you want to run a WebJob in a web app by itself, with no web application running in the web app. You might want to do this in order to be able to scale your WebJob resources independently of your web application resources.
  • Use the WebJobs new-project template for a WebJob linked to a web projectCreate a project that is configured to deploy automatically as a WebJob when a web project in the same solution is deployed. Use this option when you want to run your WebJob in the same web app in which you run the related web application.

 

  1. Click File > New Project, and then in the New Project dialog box click Cloud > Azure WebJob (.NET Framework).New Project dialog showing WebJob template
  2. Follow the directions shown earlier to make the Console Application project an independent WebJobs project.
  1. Right-click the web project in Solution Explorer, and then click Add > New Azure WebJob Project.New Azure WebJob Project menu entry

    The Add Azure WebJob dialog box appears.

  2. Complete the Add Azure WebJob dialog box, and then click OK.

Deploy a WebJobs project

A WebJobs project that you have linked to a web project deploys automatically with the web project. For information about web project deployment, see How-to guides > Deploy app in the left navigation.

To deploy a WebJobs project by itself, right-click the project in Solution Explorer and click Publish as Azure WebJob….

Publish as Azure WebJob

For an independent WebJob, the same Publish Web wizard that is used for web projects appears, but with fewer settings available to change.

After it is created, in Program.cs

static JobHost Host = null;

static void Main()
{

var config = new JobHostConfiguration();

if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}

Host = new JobHost(config);

//Place Your code here if we want to execute a specific method after the job is triggered like below.

Host.RunAndBlock();

}

After we build the project, create a release.

Now from the Windows Azure panel, we can configure it using steps below.

Create a continuous WebJob

  1. In the Azure portal, go to the App Service page of your App Service web app, API app, or mobile app.
  2. Select WebJobs.Select WebJobs
  3. In the WebJobs page, select Add.WebJob page
  4. Use the Add WebJob settings as specified in the table.Add WebJob page

    Using Steps above, Webjob will start running if its a continous trigger, other wise manually if its set as a manual trigger.

Azure WebJobs has made a potentially difficult and complex feature an easy and simple one to implement. It’s stable, scalable, and easy to modify as our needs change. If you haven’t checked out Azure WebJobs yet, you should, it can be used for a wide variety of needs.

C-sharp Cache Image returned from asp.net webapi

Hey folks, well recently i developed some web service that return image as file from a web service method. User pass us a URL like below:

http://www.abc.com/api/downloadfile?fileid=100&type=user

This return image of user with id=100

Lets say we list 100 users on a page, and bind this URL to image src attribute, whenever the page loads, it will make 110 calls to the service and page stays busy until all images are loaded.

To tackle this, all i did was below HIGHLIGHTED IN BOLD:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
        [HttpGet]
        [EnableCors(origins: "*", headers: "*", methods: "get", PreflightMaxAge = 600)]
        [Route("DownloadFile")]
        [Microsoft.AspNetCore.Mvc.ResponseCache(Duration = 259200)]
        public async Task<httpresponsemessage> DownloadFile(int FileId)
        {
            var result = Task.Factory.StartNew(() =>
            {
                var regact = DownloadFileContent(FileId); //returns us the bytes of file based on Id provided.
                return regact;
            });
 
            await result;
 
            if (result.Result == null)
            {
                HttpResponseMessage resultNoFile = new HttpResponseMessage(HttpStatusCode.NoContent);
                return resultNoFile;
            }
            else
            {
                byte[] fileContent = Convert.FromBase64String(result.Result.DocumentBody);
 
                HttpResponseMessage results = new HttpResponseMessage(HttpStatusCode.OK);
                var stream = new System.IO.MemoryStream(fileContent);
                results.Content = new StreamContent(stream);
                results.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(result.Result.MimeType);
 
                results.Headers.CacheControl = new CacheControlHeaderValue
                {
                    Public = true,
                    MaxAge = TimeSpan.FromSeconds(259200)
                };
 
                results.Headers.Add("Cache-Control", "public, max-age=259200");
                return results;
            }
        }
</httpresponsemessage>

Added following attribute to method

[Microsoft.AspNetCore.Mvc.ResponseCache(Duration = 259200)]

and following chunk into the code block.

results.Headers.CacheControl = new CacheControlHeaderValue
{
Public = true,
MaxAge = TimeSpan.FromSeconds(259200)
};

results.Headers.Add(“Cache-Control”, “public, max-age=259200”);

After this first time we load images from service and next time from disk cache.

Dynamics CRM, set status of activity as Complete/Open using CSharp

In dynamics CRM, Task, phonecalls or any activity can be marked as complete which indicate its status as done.

To programatically, do it from C#, below code is required. Lets first make a generic entity model to be used.

1
2
3
4
5
6
7
8
9
    public class ActivityStatusInputEntity
    {
        public string Email { get; set; }
        public string Password { get; set; }
        public string ActivityId { get; set; }
        public string ActivityType{get;set;} //task, phonecall, meeting ..
        public int StatusCode { get; set; } // 5 if its a tasks, 2 if its a call, 3 if its a meeting
        public int StateCode { get; set; } // 0 to set it as open activity, 1 to make it Completed
    }

StatusCode and StateCode are the major key points here. As we cannot update these fields directly into the entity, we can do this with the SetStateRequest class.

StatusCode: 5 if its a tasks, 2 if its a call, 3 if its a meeting
StateCode: 0 to set it as open activity, 1 to make it Completed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
public Response UpdateTaskStatus(ActivityStatusInputEntity activityStatusEntity)
        {
            try
            {
                var crmService = GetCRMService(activityStatusEntity.Email, activityStatusEntity.Password);
                SetStateRequest setStateRequest = new SetStateRequest();
 
                // In my case i'm updating Task Activity
                setStateRequest.EntityMoniker = new EntityReference(activityStatusEntity.ActivityType, new Guid(activityStatusEntity.ActivityId));
 
                // Set the State and Status OptionSet Values.
                setStateRequest.State = new OptionSetValue(taskStatusEntity.StateCode);
                setStateRequest.Status = new OptionSetValue(taskStatusEntity.StatusCode);
 
                // Execute the Response
                SetStateResponse setStateResponse = (SetStateResponse) crmService.Execute(setStateRequest);
                return new Response() {Message = "success"};
            }
            catch (Exception err)
            {
                return new Response() {Message = "failure"};
            }
 
        }

This way we can set status of activities to either complete, or reopen an activity for editing programatically in C#.

Dynamics CRM, Update Task using C#

In dynamics CRM, a task, phone call, meeting are termed as activities performed on an entity. Like if there is an entity “Lead”, under a certain lead there can be multiple activities like tasks, phonecalls, appointments e.t.c

Let us update a task in dynamics CRM created in prior post.

First we will define a task DTO(Data transformation Object) or model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
public class UpdateTaskEntity
    {        
        public string Id { get; set; }
        public string RegardingObjectName { get; set; }
        public string RegardingObjectId { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string OwnerId { get; set; }
        public string Subject { get; set; }
        public string Description { get; set; }
        public DateTime ScheduledStart { get; set; }
        public DateTime ScheduledEnd { get; set; }
        public string Priority { get; set; }
        public double Duration { get; set; }
    }

GetCRMService object can be referenced from following post LINK TO PART 1

Property Id represents the Id (guid) of the task
ReferenceObjectId and ReferenceObjectName are important, as they represents the object to which this task will be added under. Like if you are to add a task under a Lead, then type referenceobjectname as “lead” and ReferenceObjectId as Id of the lead entity object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
public Response AddTask(UpdateTaskEntity task)
        {
            try
            {
                var crmService = GetCRMService(task.Email, task.Password);
                var setupTask = new Entity("task");
                setupTask.Id = new Guid(task.Id);
                setupTask.Attributes["ownerid"] = new EntityReference("systemuser", new Guid(task.OwnerId));
                setupTask.Attributes["regardingobjectid"] = new EntityReference(task.RegardingObjectName,
                    new Guid(task.RegardingObjectId));
                setupTask.Attributes["subject"] = task.Subject;
                setupTask.Attributes["description"] = task.Description;
                setupTask.Attributes["createdon"] = DateTime.Now.ToLocalTime();
 
                //setupTask.Attributes["scheduledstart"] = task.ScheduledStart;
                setupTask.Attributes["scheduledend"] = task.ScheduledEnd.AddHours(23).AddMinutes(59).AddSeconds(59);
                setupTask.Attributes["prioritycode"] =
                    new Microsoft.Xrm.Sdk.OptionSetValue(Convert.ToInt32(task.Priority));
                setupTask.Attributes["actualdurationminutes"] = Convert.ToInt32(task.Duration);
                crmService.<strong>Update</strong>(setupTask);
                return new Response() { Message = "success" };
            }
            catch (Exception err)
            {
                return new Response() { Message = "failure" };
            }
        }

Dynamics CRM, Create a task using C#

In dynamics CRM, a task, phone call, meeting are termed as activities performed on an entity. Like if there is an entity “Lead”, under a certain lead there can be multiple activities like tasks, phonecalls, appointments e.t.c

Let us create a task in dynamics CRM.

First we will define a task DTO(Data transformation Object) or model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
public class TaskEntity
    {        
        public string RegardingObjectName { get; set; }
        public string RegardingObjectId { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string OwnerId { get; set; }
        public string Subject { get; set; }
        public string Description { get; set; }
        public DateTime ScheduledStart { get; set; }
        public DateTime ScheduledEnd { get; set; }
        public string Priority { get; set; }
        public double Duration { get; set; }
    }

GetCRMService object can be referenced from following post LINK TO PART 1

ReferenceObjectId and ReferenceObjectName are important, as they represents the object to which this task will be added under. Like if you are to add a task under a Lead, then type referenceobjectname as “lead” and ReferenceObjectId as Id of the lead entity object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
public Response AddTask(TaskEntity task)
        {
            try
            {
                var crmService = GetCRMService(task.Email, task.Password);
                var setupTask = new Entity("task");
 
                setupTask.Attributes["ownerid"] = new EntityReference("systemuser", new Guid(task.OwnerId));
                setupTask.Attributes["regardingobjectid"] = new EntityReference(RegardingObjectName,
                    new Guid(task.RegardingObjectId));
                setupTask.Attributes["subject"] = task.Subject;
                setupTask.Attributes["description"] = task.Description;
                setupTask.Attributes["createdon"] = DateTime.Now.ToLocalTime();
                setupTask.Attributes["scheduledstart"] = task.ScheduledStart;
                setupTask.Attributes["scheduledend"] = task.ScheduledEnd.AddHours(23).AddMinutes(59).AddSeconds(59); // Adding end time as one day ahead of current time
                setupTask.Attributes["prioritycode"] =
                    new Microsoft.Xrm.Sdk.OptionSetValue(Convert.ToInt32(task.Priority));
                setupTask.Attributes["actualdurationminutes"] = Convert.ToInt32(task.Duration);
                crmService.Create(setupTask);
                return new Response() {Message = "success"};
            }
            catch (Exception err)
            {
                return new Response() {Message = "failure"};
            }
        }