Reading a Jira 6 tasklist in .NET
Tags: dotnet, csharp, 5days5blogposts
Published: 2021-04-21 12:35:50

While automating some tasks during my software maintenance job, I thought it would be useful to be able to read the current task list straight from Jira. Our client is hosting instance of older version of Jira, about 6.X, so it still can show you a very simple filtered list, where every row in a table is a different task. It's not very complicated, but I could use it to further automate some processes, for example by automatically generate a possible solution to problems every morning, before I even wake up. 

Or maybe to create an ASP.NET app which could generate a fix script given a single input, and after reading the task list, additionally it could give me ID of the task I just solved, and sample comment to write if it's very common case? 

Either way, I thought it might be useful knowledge to someone looking to automate his job while being forced to use an older version of Jira. 

## What do you need?

Just your regular .NET SDK. Note that in my case I've been using .NET 5, but I think all of my code should work the same or with little differences in the earlier version of .NET, so it should be possible to easily reproduce in either .NET Core or .NET Framework 4.x

## Steps

The only problem you might encounter while reading from Jira is the fact that you need to be logged in in order to read anything, so:

1. Log in to Jira using HttpClient
2. Read the task list in any way you want.

## Logging in

To log in programmatically to Jira, you have to first check, how do you do it normally - through a browser. In my case, when I clicked "login", a request was sent to https://{LocalJiraUrl}/login.jsp with the following body:

```json
{
	"os_username": "login",
	"os_password": "password",
	"os_destination": "",
	"user_role": "",
	"atl_token": "",
	"login": "Zaloguj się"
}
```

Let's take a closer look at this JSON:

- os_username, os_password - Obviously, normally these would be my login and password to Jira system.
- os_destination - I didn't investigate this deeper, but I suspect it would matter more if I tried to access some part of Jira, like a specific task, and was redirected to login page to authorize, to later by redirected to the page I tried to access in the first place.
- user_role, atl_token - not sure what those two could be, and in what situations they would be used by Jira
- login - It seems that this field passes a string written on login button, which in my case was "login" translated to Polish.

This one look simple enough to replicate - we just need to fill in username, password and probably login fields, and we'll be done. Right?

Sadly, no, there is one more thing to take care of: Cookies. For this to work, every request have to use cookies provided by Jira on the first GET request you make to their website. For the sake of knowledge, I will say that there are two: JSESSIONID and atlassian.xsrf.token. Good news is, we don't need their names, or any other information about them, when we write our code - we only have to remember that they are there, and we have to take care of them Let's look at the following code:

```csharp
var cookies = new CookieContainer();
var handler = new HttpClientHandler();
handler.CookieContainer = cookies;

var client = new HttpClient(handler);
var result = client.GetAsync("https://{LocalJiraUrl}/login.jsp").Result;
```

Now let's analyze it step by step:

1. We created and initialized a new CookieContainer object
2. We created and initialized a new HttpClientHandler, which can be used as an optional argument in HttpClient constructor
3. We set CookieContainer in our HttpClientHandler to our freshly initialized CookieContainer
4. We created and initialized HttpClient using our HttpClientHandler.
5. We made a simple GET request to Jira. The fact that it's async is not important, as we immediately ask for .Result - new versions of .NET simply don't have synchronous Get method for HttpClient class.

Why did we do all this? So that when we make a GET request to Jira, we don't need to bother ourselves to look for specific cookies by their names in response that we got. This way any cookie from Jira response is automatically added to our CookieContainer, and we don't have to bother ourselves with them in any way. 

Now we just prepare form data and post them to login page, and we're done:

```csharp
var form = new Dictionary<string, string>
{
    {"os_username", login},
    {"os_password", password},
    {"os_destination", string.Empty},
    {"user_role", string.Empty},
    {"atl_token", string.Empty},
    {"login", "Zaloguj się"}
};

var response = client.PostAsync("https://{LocalJiraUrl}/login.jsp", new FormUrlEncodedContent(form)).Result;
```

And so, we are logged in. Time to get the tasks.

## Read the task list

I have to admit: I'm lazy, so I won't make my life any harder than it needs to be. A version of Jira I'm working on allows me to simply export my filtered list of tasks in XML or RSS format. I just make a GET request using our logged in HttpClient to access the XML version of task list, and save it to the file:

```csharp
var xmlResult = client
    .GetStringAsync(
        "https://{LocalJiraUrl}/sr/jira.issueviews:searchrequest-xml/20030/SearchRequest-20030.xml?tempMax=10000")
    .Result;

var path = "C:\\Users\\[username]\\Desktop\\test.xml";

File.WriteAllText(path, xmlResult);
```

All this does is hit a link XML result for filter 200300 (it's the ID of filter I used to get my daily tasks), get content as string using HttpClient.GetStringAsync(), and write it to file. 

Of course, this is a simplified example - we could now Deserialize it to custom prepared class, and read it to our application to make processing of any kind, or put it in our local SQL Server Express database, or use any other method of storing this data in simplified format, so that we can use it at a later time. 

## Summary

- In older version of Jira (which I believe are still commonly used) you can access task list programmatically
- I did it only because I couldn't find any easily-accessible API in this Jira instance, so I had to get creative
- If you want to automate your job, this might make your life a bit easier.
- Cookies can't be avoided, but you can simplify handling them using HttpClientHandler.