<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jakub Rumpel</title>
    <description>The latest articles on DEV Community by Jakub Rumpel (@hanewali).</description>
    <link>https://dev.to/hanewali</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F617262%2Fd98c242b-fdfd-40ec-a2ed-250d3cfc0302.jpg</url>
      <title>DEV Community: Jakub Rumpel</title>
      <link>https://dev.to/hanewali</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hanewali"/>
    <language>en</language>
    <item>
      <title>Adding specific certificate to HttpClient in .NET 6</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Wed, 31 Aug 2022 09:34:58 +0000</pubDate>
      <link>https://dev.to/hanewali/adding-specific-certificate-to-httpclient-in-net-6-n07</link>
      <guid>https://dev.to/hanewali/adding-specific-certificate-to-httpclient-in-net-6-n07</guid>
      <description>&lt;p&gt;For the last few days, I was dealing with an issue that wouldn't let me rest. My job requires me to use smartcard to authorize access to some of the internal services. That's not a problem when I use a browser like Chrome or Firefox, but becomes an issue when I want to use these services through their API to automate something really boring.&lt;/p&gt;

&lt;p&gt;Of course, the smartcard itself only serves the purpose of authorizing usage of the certificate that's already installed off of it in my personal certificate store on Windows, but I still have to somehow add it to my request. &lt;/p&gt;

&lt;p&gt;Required steps, then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Access the certificate store&lt;/li&gt;
&lt;li&gt;Find my certificate&lt;/li&gt;
&lt;li&gt;Add it to the HttpClient&lt;/li&gt;
&lt;li&gt;Successfully perform a request&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Seems simple enough, so let's get to it. First, I have to access my personal certificate store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;X509Store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StoreLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OpenFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadOnly&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two lines first create an object to access a personal store of a current user, and then open it in ReadOnly mode. We don't need the right to change anything, so ReadOnly will suffice.&lt;br&gt;
Now, let's find our certificate. In my example, the easiest way is to use the IssuerName, because there is only one with this specific name. In yours, you might want to find another property that suits you better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;certificate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Certificates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IssuerName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"ISSUER_NAME"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line finds the first certificate with IssuerName that fits our requirements. Now that we have it, let's add it to the client. &lt;br&gt;
In order to do that, we first have to create an HttpClientHandler(), which will then be used to create an HttpClient() object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;clientHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClientHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;clientHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientCertificates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, between creating a Handler and using it to create a Client, we added the certificate to it. Now we don't have to worry about it anymore, because the Client will use it by default.&lt;br&gt;
The rest of the work is to perform a request in a standard manner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://service.service"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/endpoint"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This request will use our added certificate to authorize itself with a service, and everything should work just fine. The problem is solved, and now I can automate my really boring tasks - and so can you ;)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was first published on my personal blog &lt;a href="https://rumpel.dev"&gt;https://rumpel.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Git can cause problems with vim-plug!</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Fri, 20 May 2022 14:45:10 +0000</pubDate>
      <link>https://dev.to/hanewali/git-can-cause-problems-with-vim-plug-2dl5</link>
      <guid>https://dev.to/hanewali/git-can-cause-problems-with-vim-plug-2dl5</guid>
      <description>&lt;p&gt;Or rather, bad configuration can do it.&lt;/p&gt;

&lt;p&gt;See, I’ve just spent about an hour trying to figure this out, and for the life of me I couldn’t understand, what was happening.&lt;/p&gt;

&lt;p&gt;I’ve recently fallen in love with the idea of adding new features to Vim using plugins. As I have four different machines running Linux in one way or another, I have decided to install the same two plugins (Ale and NerdTree) on all of them. Sounds simple enough, doesn’t it? And it was really simple!&lt;/p&gt;

&lt;p&gt;On three out of four machines it worked perfectly. One command to install plug-vim on machine, copy the right section into my .vimrc… simple enough, it worked. Right until I tried to install it on my fourth, final and most important machine: Ubuntu in WSL2 on my personal laptop.&lt;/p&gt;

&lt;p&gt;For reasons unknown to me at the time, every time I’ve tried to install plugins, I just got these errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error detected while processing /home/hane/.vim/plugged/nerdtree/plugin/NERD_tree.vim:
line 15:
E492: Not an editor command: ^M
line 16:
E15: Invalid expression: exists('loaded_nerd_tree')^M
line 235:
E171: Missing :endif
Error detected while processing /home/hane/.vim/plugged/ale/plugin/ale.vim:
line 4:
E492: Not an editor command: ^M
line 6:
E492: Not an editor command: ^M
line 7:
E15: Invalid expression: exists('g:loaded_ale_dont_use_this_in_other_plugins_please')^M
line 353:
E171: Missing :endif
Press ENTER or type command to continue

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They showed up every time I opened Vim, too, so nothing too pleasant.&lt;/p&gt;

&lt;h2&gt;
  
  
  The culprit was good ol’ Git.
&lt;/h2&gt;

&lt;p&gt;It took me more than an hour to find the right way to google this, and kudos to this specific &lt;a href="https://github.com/vim/vim/issues/6156#issuecomment-1001134641"&gt;comment&lt;/a&gt; for helping me!&lt;/p&gt;

&lt;p&gt;The fix was simple: Change git configuration and set property core.autocrlf to false.&lt;/p&gt;

&lt;p&gt;One command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global core.autocrlf false

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And after reinstalling plugins once again, all my problems were gone!&lt;/p&gt;

&lt;h2&gt;
  
  
  So what happened?
&lt;/h2&gt;

&lt;p&gt;Vim-plug uses git to download plugins. When &lt;strong&gt;core.autocrlf&lt;/strong&gt; was set to &lt;strong&gt;true&lt;/strong&gt; , it automatically set line endings for every file to CRLF, while Vim, when processing .vim files on Linux, was expecting LF endings. That caused the problem above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;E492: Not an editor command: ^M

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But what is an ^M, and what does it have to do with Line Endings?
&lt;/h2&gt;

&lt;p&gt;^M is a CR in CRLF, which stands for Carriage Return. It’s a control character used to move a cursor to the beginning of the next line when reaching the end of a current line. As you can probably guess, it was not expected in this case, because only ^@ (Line Feed, LF in CRLF) was expected by Vim and the end of the line.&lt;/p&gt;

&lt;p&gt;So Vim got one more character than expected and wasn’t ready to process it, effectively being unable to run installed plugins.&lt;/p&gt;

&lt;p&gt;Of course, I could’ve spent much less time on fixing that, if I knew what ^M was beforehand, but hey - We’re all learning, right?&lt;/p&gt;

&lt;p&gt;If you encountered this issue too, and this article helped you, please let me know!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally posted on my personal website &lt;a href="https://rumpel.dev"&gt;Rumpel.dev&lt;/a&gt;. You can find more posts and informations about me there!&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Code stupid things</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Wed, 26 Jan 2022 04:48:25 +0000</pubDate>
      <link>https://dev.to/hanewali/code-stupid-things-51k2</link>
      <guid>https://dev.to/hanewali/code-stupid-things-51k2</guid>
      <description>&lt;p&gt;Today I’ve watched new &lt;a href="https://www.youtube.com/watch?v=ldaescGA1dY&amp;amp;t=835s"&gt;video from CodeBullet&lt;/a&gt;: Channel that I found when I had a huge phase on watching everything AI - be it teaching a neural network to play a Mario game or drive a simple car... anything like that, and CodeBullet provided me with exactly such a material: simple or not so simple task with an interesting enough narration. &lt;/p&gt;

&lt;p&gt;The video was about creating a simple program to cheat in “Clicker Heroes” game. While I don’t know this game, and didn’t want to download it, it reminded me a little bit of an old in-browser clicker game called &lt;a href="https://orteil.dashnet.org/cookieclicker/"&gt;“Cookie Clicker”&lt;/a&gt;. There was a time when I spent too much time there, so I was happy to notice it’s still up and online as of writing this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is this about, really?
&lt;/h2&gt;

&lt;p&gt;After finding the game again I realized that I’m curious about my ability to code something like this: simple clicker to cheat the game, as a fun project. 3 AM be damned, I took a laptop and started coding. Finding whether I was in a game, clicking a cookie, check for upgrades and buying them... all of that in a language I didn’t touch in a long while: Python. &lt;/p&gt;

&lt;p&gt;Two and a half hours later, and the code - as simple and unpolished as it is - is done and working. Cookies are clicked, upgrades are being bought and I can watch and smile, as I see my code working without problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  And then I remembered.
&lt;/h2&gt;

&lt;p&gt;Coding used to be really fun for me. Such small projects, just to achieve simple objective, overcome a simple challenge. For the last two and a half years of my professional career, I stopped coding just for fun. Projects like this weren’t really in my head, while I had to focus on building my independent life which I’ve then just begun and code I was working on at any company I was currently working at. &lt;/p&gt;

&lt;p&gt;My point is, I forgot that I’ve got into coding to have fun; To overcome those little challenges, to see my work come to any kind of fruition. Of course, there were other sources of motivation, biggest of which was my desire to make people’s life easier using what I have learned, but this? This is where it all started. Simple pleasure from fulfilling a simple task using code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Remember to code small, stupid things.
&lt;/h2&gt;

&lt;p&gt;It’s just never boring. There is always something you can do to just... do a thing. Some stupid challenge, like making your computer react to you in some way. Or any kind of automation, like turning off your console at the specified time in case you left it in rest mode. Or anything else that will probably take you less then two hours, but will flood your brain with dopamine. My point is, remember that coding, like any other work, can be used both professionally and just for fun, for the simple pleasure of Doing The Thing. If you can make your life easier while you do that, it’s just gravy. &lt;/p&gt;

&lt;p&gt;Just remember to have fun. &lt;/p&gt;

&lt;p&gt;PS. For those curious, you can find the code I wrote &lt;a href="https://github.com/Hanewali/CookieCheater"&gt;here&lt;/a&gt;. Word of warning: It’s not pretty or polished, I’m not a daily Python developer. It was just the easiest language to quickly achieve this objective, and I like writing simple scripts of this kind in Python.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>Setting up a .NET service on Linux</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Tue, 11 May 2021 20:58:23 +0000</pubDate>
      <link>https://dev.to/hanewali/setting-up-a-net-service-on-linux-3hc0</link>
      <guid>https://dev.to/hanewali/setting-up-a-net-service-on-linux-3hc0</guid>
      <description>&lt;p&gt;This is another "I don't want to have to google this anymore" kind of post.&lt;/p&gt;

&lt;p&gt;Quick sidenotes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I use .NET 5&lt;/li&gt;
&lt;li&gt;I didn't create the example &lt;em&gt;.service&lt;/em&gt; file; I couldn't find the original author, as it probably was from Stack Overflow, but this is the file I use on my VPS.&lt;/li&gt;
&lt;li&gt;This completely doesn't cover setting up nginx or writing actual code - just creates a service which runs your .NET app&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create .service file
&lt;/h3&gt;

&lt;p&gt;My &lt;em&gt;.service&lt;/em&gt; files are stored in &lt;strong&gt;/etc/systemd/system/&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sample &lt;em&gt;.service&lt;/em&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;Unit]
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Sample Description

&lt;span class="o"&gt;[&lt;/span&gt;Service]
&lt;span class="c"&gt;# systemd will run this executable to start the service, has to be specific file&lt;/span&gt;
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/srv/AppDir/AppExecutable

&lt;span class="c"&gt;# to query logs using journalctl, set a logical name here&lt;/span&gt;
&lt;span class="nv"&gt;SysLogIdentifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SampleName

&lt;span class="c"&gt;# use your username to keep things simple&lt;/span&gt;
&lt;span class="c"&gt;#make use user you chose has the correct permissions to run the app&lt;/span&gt;
&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;username

&lt;span class="c"&gt;#this environment variable is neccessary when dotnet isn't loadeed for the specified user. &lt;/span&gt;
&lt;span class="c"&gt;#to figure out this variable, run 'env | grep DOTNET_ROOT' when dotnet has been loaded into your shell&lt;/span&gt;
&lt;span class="c"&gt;#Environment="DOTNET_ROOT=/opt/rh/rh-dotnet31/root/usr/lib64/dotnet"&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;Install]
&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Description - this will be shown as a description when you run systemctl status ServiceName.service, useful in order to identify the service&lt;/li&gt;
&lt;li&gt;ExecStart - This has to be a direct path to the executable file of your app. Make sure you made it executable using &lt;strong&gt;chmod +x&lt;/strong&gt;!&lt;/li&gt;
&lt;li&gt;SysLogIdentifier - Name of the app used in syslog - again, useful to identify your app later&lt;/li&gt;
&lt;li&gt;User - Username of the user who "runs" the app. Preferably use your own, but you can use any as long as specified user has the correct permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Register the service
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, check if systemctl command properly sees your .service file:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status ServiceName.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If results seems okay (Description is shown, and it seems like everything is okay), start your service&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start ServiceName.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aaand that's it! From this point on, you just have to make sure your code is good, and test if your app works!&lt;/p&gt;

&lt;p&gt;Have a great day ;)&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>linux</category>
    </item>
    <item>
      <title>Be careful using ROLLBACK on nested transaction in SQL Server!</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Mon, 10 May 2021 13:52:09 +0000</pubDate>
      <link>https://dev.to/hanewali/be-careful-using-rollback-on-nested-transaction-in-sql-server-2b5p</link>
      <guid>https://dev.to/hanewali/be-careful-using-rollback-on-nested-transaction-in-sql-server-2b5p</guid>
      <description>&lt;p&gt;This is something I've learned today, and was pretty irritated to find out.&lt;/p&gt;

&lt;p&gt;Up to this day I was sure that ROLLBACK TRANSACTION in nested transactions will only roll back highest, most recent transaction. To my surprise, something else happens. Consider following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
    &lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you know what will happen?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First and second transaction will be created&lt;/li&gt;
&lt;li&gt;BOTH First and second transaction will be rolled back&lt;/li&gt;
&lt;li&gt;A "The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION." error will be thrown.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a warning: Be careful when rolling back nested transactions. It doesn't matter if transactions are named or how many are there - ROLLBACK  will roll back all of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  When do you use nested transactions?
&lt;/h3&gt;

&lt;p&gt;The easiest example I can think of is when you call a procedure from a different procedure, and you have transactions in both those procedures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--this is a very simplified example&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;Proc1&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
        &lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;Proc2&lt;/span&gt;
    &lt;span class="k"&gt;COMMIT&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;Proc2&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
    &lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there are two nested transactions here, and both will be rolled back because of ROLLBACK TRAN statement in Proc2, leading to an error being thrown when we get to COMMIT TRAN statement.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can you avoid the error message?
&lt;/h3&gt;

&lt;p&gt;There are two ways I find most likely to be useful:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Check @@trancount before committing transaction&lt;/p&gt;

&lt;p&gt;This is simple enough: When you get to committing all the changes you've made in the transaction, check if there are still transactions left to be committed. Check the following code:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--this is a very simplified example&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;Proc1&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
        &lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;Proc2&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;trancount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt;
        &lt;span class="k"&gt;COMMIT&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;Proc2&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
    &lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;With this newly added IF in Proc1, the COMMIT statement won't be called, because there will be no transactions left to commit detected by our condition.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use only one rollback in CATCH statement&lt;/p&gt;

&lt;p&gt;Sometimes you can avoid such problem by removing transaction from nested procedure, and instead using RAISERRROR and BEGIN TRY/BEGIN CATCH statements. Check the following code:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;Proc1&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRY&lt;/span&gt;
        &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
            &lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;Proc2&lt;/span&gt;
        &lt;span class="k"&gt;COMMIT&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;TRY&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;CATCH&lt;/span&gt;
        &lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="n"&gt;TRAN&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;CATCH&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;Proc2&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="n"&gt;RAISERROR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Sample error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;--numbers are examples for severity and state&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In this example, rollback will only happen when there will be and error in Proc2 - leading to a situation when we have one master transaction, which can be rolled by only by throwing an error. Of course, we can also roll it back earlier and handle such a case however we see fit. This is just an example of how you can avoid problems with rolling back a nested transaction.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Sidenotes:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I'm aware that in new applications THROW is preferred to RAISERROR, but sadly I haven't used it yet, so I decided to use old statement for now&lt;/li&gt;
&lt;li&gt;This post completely ignores the existence of &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/set-xact-abort-transact-sql?view=sql-server-ver15"&gt;XACT_ABORT&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/xact-state-transact-sql?view=sql-server-ver15"&gt;XACT_STATE&lt;/a&gt; - you can learn more about those under provided links. I encourage you to do so: They can make managing your transactions much easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Be careful when rolling back nested transactions&lt;/li&gt;
&lt;li&gt;ROLLBACK statement always rolls back every transaction you have in your current session.&lt;/li&gt;
&lt;li&gt;You can deal with lack of transactions by checking for @@trancount or removing nested transactions and using RAISERROR or THROW&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Transactions in SQL Server are still a difficult subject for me, so if I made any mistake, please, let me know!&lt;/p&gt;

</description>
      <category>sql</category>
    </item>
    <item>
      <title>Quick-start SQL Server 2019 in Docker</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Sun, 25 Apr 2021 17:04:07 +0000</pubDate>
      <link>https://dev.to/hanewali/quick-start-sql-server-2019-in-docker-26p4</link>
      <guid>https://dev.to/hanewali/quick-start-sql-server-2019-in-docker-26p4</guid>
      <description>&lt;p&gt;It's not any kind of magic, but every time I have to do it, I find myself googling for the exact command again and again, So I decided to just save it here - for me, later, and for anyone else who want to paste a command into the terminal and be done with it.&lt;/p&gt;

&lt;p&gt;I assume that you already have Docker installed, but in case you don't, there is a great tutorial for Windows &lt;a href="https://docs.docker.com/docker-for-windows/install/"&gt;here&lt;/a&gt;, or for Ubuntu &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04"&gt;here&lt;/a&gt; on how to do it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"ACCEPT_EULA=Y"&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"SA_PASSWORD=&amp;lt;YourStrong@Passw0rd&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-p&lt;/span&gt; 1433:1433 &lt;span class="nt"&gt;--name&lt;/span&gt; YourContainerName &lt;span class="nt"&gt;-h&lt;/span&gt; ContainerHostname &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-d&lt;/span&gt; mcr.microsoft.com/mssql/server:2019-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need any additional information, check out &lt;a href="https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-ver15&amp;amp;pivots=cs1-bash"&gt;this page&lt;/a&gt; for details about arguments and passed values. &lt;/p&gt;

&lt;p&gt;REMEMBER: Password has to be compliant with SQL Server default password policy: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By default, the password must be at least 8 characters long and contain characters from three of the following four sets: Uppercase letters, Lowercase letters, Base 10 digits, and Symbols&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To check if your container works properly, see it's status using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you can't see it, run it with "-a" argument to see if it's shut down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have any trouble starting the image, you can see container log by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs YourContainerName 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>sql</category>
      <category>docker</category>
    </item>
    <item>
      <title>Avoid SQL Server scalar-valued functions in WHERE statements at all cost!</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Fri, 23 Apr 2021 19:01:41 +0000</pubDate>
      <link>https://dev.to/hanewali/avoid-scalar-valued-functions-in-where-statements-at-all-cost-4klh</link>
      <guid>https://dev.to/hanewali/avoid-scalar-valued-functions-in-where-statements-at-all-cost-4klh</guid>
      <description>&lt;p&gt;This one requires a little intro. &lt;/p&gt;

&lt;p&gt;First, you have to understand what a scalar value does: It returns a single value. It can be an INT, a BIT or even a whole NVARCHAR with hundreds of characters, but it will return only one full value, and never a set of them. If you need a set of values, use table functions.&lt;/p&gt;

&lt;p&gt;Secondly, there is a certain order to SQL queries that you have to know about. More info about this order and exceptions from it can be found &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/select-transact-sql?view=sql-server-ver15#logical-processing-order-of-the-select-statement"&gt;here&lt;/a&gt;, but the short lesson is that if you have a SELECT FROM WHERE query, the order of operations will be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;FROM&lt;/li&gt;
&lt;li&gt;WHERE&lt;/li&gt;
&lt;li&gt;SELECT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That means that SQL Server will first grab all possible records from chosen tables, then filter them using your conditions, and then show you the result. &lt;/p&gt;

&lt;p&gt;Third and final intro information Scalar-valued functions in WHERE statements work ONCE for every row. &lt;/p&gt;

&lt;p&gt;They work ONCE per ROW. Let that sink in, understand what it means.&lt;/p&gt;

&lt;p&gt;If your FROM statement grabs, say, 200 records, it will run a function 200 times. If it'll grab 500,000 records, that's how many times a function will run, for every single row of data you grabbed. And remember: Not just those you SELECTed, but every single cell possible.&lt;/p&gt;

&lt;p&gt;You might say "but my function only runs for a millisecond!", and you might even be right. But 500,000 times one millisecond is 500 seconds, so give or take 8 minutes. &lt;/p&gt;

&lt;p&gt;Let that sink in.&lt;/p&gt;

&lt;p&gt;My advice? Avoid them at all cost. But what if you have to use a scalar-valued function in WHERE statement? What if you think you can't live without it? Say, for example, that your user can only see some records on your table, while others shouldn't show up on the interface, and your function is something along the lines of Has_Permition(User_Id, Item_Id).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--Assume that @User_Id is declared eariler, as a procedure argument or variable&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;Item_Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Item_Name&lt;/span&gt;
    &lt;span class="n"&gt;Item_Description&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;Items&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;Has_Permission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;User_Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Item_Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What then? I've identified at least two possible solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  One: Inline your function content into query
&lt;/h2&gt;

&lt;p&gt;This isn't really intuitive, but if you do it, you make sure that your records are processed in bulk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;Item_Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Item_Name&lt;/span&gt;
    &lt;span class="n"&gt;Item_Description&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;Items&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="k"&gt;EXISTS&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;FROM&lt;/span&gt; 
                &lt;span class="n"&gt;ItemCategoryPermissions&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;ICP&lt;/span&gt;
                &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;Permissions&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ICP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Permission_Id&lt;/span&gt;
                &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;UserPermissions&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;UP&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;UP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Permission_Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;
            &lt;span class="k"&gt;WHERE&lt;/span&gt;
                &lt;span class="n"&gt;ICP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Category_Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Category_Id&lt;/span&gt;
                &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;UP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User_Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;User_Id&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's stop here for a second and analyze this query.&lt;/p&gt;

&lt;p&gt;Instead of checking every single Item_Id in Has_Permission, which, depending on the number of items, could take forever, and check every item at once in this kind of bulk query. &lt;/p&gt;

&lt;p&gt;Now, I get why one would want to avoid that, because it defies the basic idea of using functions in programming - to avoid code repetitions. However, in SQL sometimes it's better to write code like this in the name of performance. Of course, it depends on the specific case: If it's part of a job running once a day, you might care less for performance, and more for nice, maintainable code. However, if you're running a stored procedure straight from user-facing interface, to show someone  a table filled with data, performance is a top priority - and this is how you can achieve it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Two: Minimize number of records processed through function.
&lt;/h2&gt;

&lt;p&gt;You can achieve this in many ways, but there are two main ones I lean to.&lt;/p&gt;

&lt;p&gt;First, and the one I prefer, is to use a Common Table Expression, or CTE for short, and get only records that are relevant for this specific search. For example, if your search window only look for a specific category of item, you could restrict the number of items to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;ExampleCte&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Description&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;Items&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Category_Id&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;Description&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;ExampleCte&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;Has_Permission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;User_Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way records going into Has_Permission function will be limited to a specific category of items, so it won't be called as many times. &lt;/p&gt;

&lt;p&gt;Another version of this query would be using tempdb table, but that's just an implementation and preference choice.&lt;/p&gt;

&lt;p&gt;From my experience, if you need performance, the first option is always better, as it processes records in bulk, instead of doing them one after another. You should still analyze what is the best option in your specific case. That being said, be wary of scalar-valued functions, as they can make a big mess if you strive for the most optimal code!&lt;/p&gt;

&lt;h2&gt;
  
  
  SQL Server 2019 User-Defined Functions Inlining
&lt;/h2&gt;

&lt;p&gt;For the sake of being thorough, I have to touch this subject.&lt;/p&gt;

&lt;p&gt;What is UDF Inlining? Microsoft added it to the SQL Server 2019 to get rid of performance problems caused by scalar functions in queries. It's supposed to do our solution one: Inline the body of the function to main query, and make the whole thing perform better. However, there is a big problem.&lt;/p&gt;

&lt;p&gt;It rarely works.&lt;/p&gt;

&lt;p&gt;I've seen in it action, and it broke most of stored procedures in a freshly migrated project. It could destroy something in your project or not, but be warned: It can make a big mess. &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Scalar-Valued Functions in WHERE statements are a big performance hit&lt;/li&gt;
&lt;li&gt;You can easily inline them by hand or minimize the problem by restricting the amount of data processed by those functions&lt;/li&gt;
&lt;li&gt;You can try to use UDF Inlining in SQL Server 2019, but you risk breaking every single stored procedure in your database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Did you have the same experience with scalar functions in SQL Server? What are your ways of optimizing it? Please, share in the comments!&lt;/p&gt;

</description>
      <category>sql</category>
      <category>5days5blogposts</category>
    </item>
    <item>
      <title>3 small tips to make your SQL Server experience easier</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Thu, 22 Apr 2021 14:29:48 +0000</pubDate>
      <link>https://dev.to/hanewali/3-tips-to-make-your-sql-server-experience-easier-5682</link>
      <guid>https://dev.to/hanewali/3-tips-to-make-your-sql-server-experience-easier-5682</guid>
      <description>&lt;p&gt;For most of the last two years, My job has been mostly about writing another and another SQL query, be it to check what's happening with some data, debug a weird error or develop a stored procedure as a part of a feature I'm working on. During that time I've written dozens of different procedures consisting of multiple queries, even to the point of committing small heresy in the form of two thousand lines monster full of XML deserialization and business validations. &lt;/p&gt;

&lt;p&gt;Bad times.&lt;/p&gt;

&lt;p&gt;But every such experience had left me with some new knowledge to use in future projects, things I could use to further optimize my SQL code or make some debugging easier, so I decided to share them in the form of this blog post&lt;/p&gt;

&lt;h2&gt;
  
  
  Easily commented out conditions
&lt;/h2&gt;

&lt;p&gt;This one is very small and simple, but very useful when I need to write a query with multiple conditions. Let's take a look at the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;Name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;SomeTable&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;Field1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"X"&lt;/span&gt;
    &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;Field2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"Y"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, here we already made our life easier by putting an AND keyword on the new line, right before second condition. It's a good practice when you're actively working on a query, because if you need to see what kind of result you'll achieve without the second condition, you can simply comment it out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;Field1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"X"&lt;/span&gt;
    &lt;span class="c1"&gt;--AND Field2 = "Y"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? Nice and easy, and in most SQL IDEs, like SSMS or DataGrip, you can comment out a single line with a simple shortcut. &lt;/p&gt;

&lt;p&gt;But what if you want to see what would happen with second condition, but without first? If you leave AND keyword on its place, you'll just create an error, because there will be no condition preceding it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--*SQL server won't let you do this, as there is no working condition before AND!*&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="c1"&gt;--Field1 = "X" &lt;/span&gt;
    &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;Field2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"Y"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, you could move AND to the end of the first condition, but then it would trouble you if you need to comment out the second condition again. Or you could comment out AND like this: /&lt;em&gt;AND&lt;/em&gt;/ and it would work, too. It's all fine and dandy, but what if there is other option?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;Field1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"X"&lt;/span&gt;
    &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;Field2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"Y"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks weird, but it could actually save you a lot of time. That way if you don't need any condition, you can simply comment it out, without breaking your whole query, which depending on size might be very difficult to find where did the error happened.  Adding this simple 1=1 will not affect your qery performance in any significant way, but instead will make it much easier to work on query "right now". &lt;/p&gt;

&lt;p&gt;Of course, it's not something I would leave in a production code, but for the sake of debugging, it can save you some precious seconds or even minutes, and most importantly, it will let you stay "in the flow", without being bothered by unexpected and irritating errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instant insert into TempDB table from SELECT
&lt;/h2&gt;

&lt;p&gt;Now this is something I've picked up just recently, but it instantly made my life much easier. Consider following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;Sample&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;Sample&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;SampleTable&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;Condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example is very simple: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We create a temporal table (which is marked by # character at the beginning of the name)&lt;/li&gt;
&lt;li&gt;We write its columns and their types&lt;/li&gt;
&lt;li&gt;We repeat both table name and columns in INSERT statement&lt;/li&gt;
&lt;li&gt;We fill it with data from SELECT statement&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It still made us write quite a lot of words, and any mistake in data type or in choosing columns in an INSERT statement can lead to irritating errors, which could stop you for a long enough time that you'll lose your focus. &lt;/p&gt;

&lt;p&gt;Instead, you could try this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt;
&lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;Sample&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;SampleTable&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;Condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes: I just replaced both CREATE TABLE and INSERT INTO statements with single INTO between SELECT and FROM statements. What does it do? It creates a table with the same column names and types as ones we just retrieved from the database using our SELECT statement, without writing a lot of unnecessary code, and making it more difficult to make a mistake in the list of columns or risking that one of the columns will have a wrong type.&lt;/p&gt;

&lt;p&gt;Of course, there is a "but": If you have to run this command multiple times, it won't just insert new data into our #Sample table, but instead it will throw an error saying that such a table already exists. We will deal with this in just a second:&lt;/p&gt;

&lt;h2&gt;
  
  
  Ensuring that unnecessary temporal table doesn't already exist
&lt;/h2&gt;

&lt;p&gt;When we use temporal tables, sometimes we also have to delete them, especially when we are actively developing our query. Of course, it's less important when we use #table in stored procedure, as it will get dropped when the procedure is finished, and it's scoped to this procedure, just as our #table will be scoped to our DB session - but if it exists when it shouldn't, it's still a problem.&lt;/p&gt;

&lt;p&gt;An obvious choice would be to simply DROP #table at the end of our query, but there is a risk: If for any reason #table doesn't exist when DROP is called, it will throw an error. Similarly, if for any reason the DROP statement won't be called (for example, because there was an error before it) next time we run our query we will also run into a problem. &lt;/p&gt;

&lt;p&gt;So what's the solution?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tempdb..#app'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single line of code will do two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if table #app already exists in tempdb&lt;/li&gt;
&lt;li&gt;If it exists, it will drop it. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Put this line at the beginning of your SQL script, change the name to whatever you like, and you're good to go. If a table doesn't exist yet, nothing will happen, but if it exists before it should, it will be dropped. &lt;/p&gt;

&lt;p&gt;This line makes an excellent work next to SELECT INTO statement, as it protects you against unnecessary errors while letting you use this statement easily.&lt;/p&gt;

&lt;p&gt;For now, this will be all. If I remember (or find out) any other tips that can make my life a bit easier, this post will have a part 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You can make debugging SQL queries much simpler by adding "fake" 1=1 condition, and putting every "real" condition after AND or OR keywords.&lt;/li&gt;
&lt;li&gt;Creating and filling tempdb tables can be very simple in SQL Server&lt;/li&gt;
&lt;li&gt;There are a lot of possible errors while operating on tempdb tables, but you can avoid them if you remember that they are there&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But what about You? Do You have any interesting tips or tricks you use in SQL Server that helps you get through the day? If you do, please share them in comments, I'd love to learn something new to use in my day-to-day SQL work.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>5days5blogposts</category>
    </item>
    <item>
      <title>Reading a Jira 6 tasklist in .NET</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Wed, 21 Apr 2021 12:35:50 +0000</pubDate>
      <link>https://dev.to/hanewali/reading-a-jira-tasklist-in-net-4ckn</link>
      <guid>https://dev.to/hanewali/reading-a-jira-tasklist-in-net-4ckn</guid>
      <description>&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;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? &lt;/p&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;h2&gt;
  
  
  What do you need?
&lt;/h2&gt;

&lt;p&gt;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&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to Jira using HttpClient&lt;/li&gt;
&lt;li&gt;Read the task list in any way you want.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Logging in
&lt;/h2&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"os_username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"os_password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"os_destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"user_role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"atl_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Zaloguj się"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a closer look at this JSON:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;os_username, os_password - Obviously, normally these would be my login and password to Jira system.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;user_role, atl_token - not sure what those two could be, and in what situations they would be used by Jira&lt;/li&gt;
&lt;li&gt;login - It seems that this field passes a string written on login button, which in my case was "login" translated to Polish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CookieContainer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClientHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CookieContainer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://{LocalJiraUrl}/login.jsp"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's analyze it step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We created and initialized a new CookieContainer object&lt;/li&gt;
&lt;li&gt;We created and initialized a new HttpClientHandler, which can be used as an optional argument in HttpClient constructor&lt;/li&gt;
&lt;li&gt;We set CookieContainer in our HttpClientHandler to our freshly initialized CookieContainer&lt;/li&gt;
&lt;li&gt;We created and initialized HttpClient using our HttpClientHandler.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;Now we just prepare form data and post them to login page, and we're done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"os_username"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"os_password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"os_destination"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"user_role"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"atl_token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Zaloguj się"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PostAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://{LocalJiraUrl}/login.jsp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FormUrlEncodedContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And so, we are logged in. Time to get the tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the task list
&lt;/h2&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;xmlResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"https://{LocalJiraUrl}/sr/jira.issueviews:searchrequest-xml/20030/SearchRequest-20030.xml?tempMax=10000"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"C:\\Users\\[username]\\Desktop\\test.xml"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xmlResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

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

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>5days5blogposts</category>
    </item>
    <item>
      <title>Accessing default system locations in .NET Core</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Tue, 20 Apr 2021 14:42:31 +0000</pubDate>
      <link>https://dev.to/hanewali/accessing-default-system-locations-in-net-core-4poi</link>
      <guid>https://dev.to/hanewali/accessing-default-system-locations-in-net-core-4poi</guid>
      <description>&lt;p&gt;During my work as a software maintainer, I often find myself writing code not as a part of my regular work, but rather to automate tasks that by definition are done manually. As I wrote last time, I despise repetitive tasks, so I created few tools to automate things like checking status of data I've sent to being processed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do I need to use locations like Desktop?
&lt;/h2&gt;

&lt;p&gt;While coding one of those automation tools, I often found myself using locations like a desktop or my home directory to store some data needed by my console applications, which are run either by task scheduler or are added to my context menu and used on a specific directory. &lt;/p&gt;

&lt;p&gt;One time I specifically decided to use Desktop, but I was worried that if I have to run it on a different computer (say, company will give developers new laptops) it would stop working and require recompiling. That's when I discovered a beautiful thing in .NET:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpecialFolder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just a simple enum with fields like Desktop, Cookies, Fonts and others. It allows you to access any directory from this enum by simply choosing one of those fields in another Environment class method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFolderPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpecialFolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Desktop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which returns string with path to a given directory. Keep in mind, that SpecialFolder is just an Enum, so &lt;strong&gt;by itself it will only return a number, not a path!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Note that some paths from this Enum will work only on Windows, while others might return confusing results on Linux systems - so your experience might be different from mine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you need to quickly get a path to a place like Desktop or user home directory, you can use Environment.SpecialFolder to make it easier.&lt;/li&gt;
&lt;li&gt;You can check the full list of SpecialFolder fields on its &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.environment.specialfolder?view=net-5.0"&gt;Microsoft page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you're deploying it on different OS than Windows, always check what kind of results you can expect using SpecialFolder.&lt;/li&gt;
&lt;li&gt;You can find some more information about using SpecialFolder on Linux on this &lt;a href="https://developers.redhat.com/blog/2018/11/07/dotnet-special-folder-api-linux/"&gt;blogpost&lt;/a&gt;. Note: It's for .NET Core 2.1&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>5days5blogposts</category>
    </item>
    <item>
      <title>Simplify and automate</title>
      <dc:creator>Jakub Rumpel</dc:creator>
      <pubDate>Mon, 19 Apr 2021 13:52:55 +0000</pubDate>
      <link>https://dev.to/hanewali/simplify-and-automate-1n1b</link>
      <guid>https://dev.to/hanewali/simplify-and-automate-1n1b</guid>
      <description>&lt;p&gt;It's only 2PM when I write this post, but the title already saved me a ton of time - in fact, enough to easily take a break to post this.&lt;/p&gt;

&lt;p&gt;After reading this post, I want you all to have a simple takeaway: If you can simplify and automate some process, you should probably do it. In fact, there is a saying within sysadmins of Reddit - "If you did it more than once, you should automate it". It is very applicable in software maintenance, where we already have to write scripts to do our job - so why not write them a bit smarter, so they can do our job for us without taking any of our time?&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened?
&lt;/h2&gt;

&lt;p&gt;An error occurred in integration between our client and systems in the other company (let's call it company B). It wasn't a critical error - but some information wasn't received on their end, which resulted in further problems that could lead to potential money loss - so the worst situation possible in corporations. &lt;/p&gt;

&lt;p&gt;Now, this kind of situation happens now and then, but usually on a much smaller scale. Once a day, maybe, a single row of data fails to be delivered properly, and has to be re-exported. I didn't automate the process of re-exporting yet, but here comes the first lesson.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplify.
&lt;/h2&gt;

&lt;p&gt;A lot of my work is done on SQL Server databases, and a lot of it is executing identical scripts with different input data. The most important thing I learned is to always save these scripts somewhere on my computer in the purest form possible, so that if I ever need it again, I can just copy and paste some numbers as an input and send it to execution - without losing an hour of time to write the same script I wrote a week or three months ago.&lt;/p&gt;

&lt;p&gt;My simplification of this problem is to keep the template for re-exporting data to company B. I have two scripts - one to check what data need to be exported, and the other for exporting. This way, all I need to do is run the first with a single number as an input, copy and paste data to the other script, and then run it. It's a few hundreds lines of SQL code every time, but it takes me approximately one minute or less to complete the task, which otherwise would take up to an hour. I plan on making them one script, but lack of time is preventing me so far from fulfilling this plan.&lt;/p&gt;

&lt;p&gt;Tip: If you work with other people in the same field, and you use the same scripts, you can easily symlink a directory from a shared location to a templates' directory of SQL Server Management Studio. Following snipped is for Windows, but it can easily be reproduced on other OS'es.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mklink /d //networkShare/DirectoryName /SSMS/TemplateDirectory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way you can easily add, edit or delete scripts, and your whole team always has the newest version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate.
&lt;/h2&gt;

&lt;p&gt;If you already have some fields where you always use the same scripts with different inputs, more often than not you can write just a bit of code, and the script can be fully automated. In my case, automation isn't full and complete yet, but it's already saving me a lot of time, which otherwise would have to be spent on boring and repetitive tasks.&lt;/p&gt;

&lt;p&gt;My automation for this problem is simple: Once I re-exported the data to company B systems, I still have to occasionally check if everything has been properly processed. This is the most boring part - every day I had to run the same scripts about ten times to check each row of data, and if processing of any is finished, pass the info to the client that we're good.&lt;/p&gt;

&lt;p&gt;All I've done was to write a piece of code to read rows of data from a TXT file and run the query for each of them. If processing of any file is complete, code emails me with the number of tasks in Jira and ID of data which was processed (as sometimes there is more than one ID in Jira task). After that, row is deleted from TXT file, and it's work there is done.&lt;/p&gt;

&lt;p&gt;All that took me about one full day to write, which I've done over the weekend, and then another day to set up and test on my work computer. Simple automation, but it's nice to wake up and see that your work is done for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it helped?
&lt;/h2&gt;

&lt;p&gt;Today an error occurred on some 40+ rows of data. Thanks to my simplification, it didn't take much time to re-export them to company B, and it won't take any of my time in coming days to make sure that everything work's swimmingly on the other end. Win-win, isn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you do it more than once, automate it.&lt;/li&gt;
&lt;li&gt;Save every script you run on your database - there is a big chance you will need it again.&lt;/li&gt;
&lt;li&gt;Use applications and functionalities that can make your life easier, like Template Library in SSMS.&lt;/li&gt;
&lt;li&gt;If you find yourself often running the same script with different input, there is a big chance you can automate it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PS. This post was inspired by Andrzej Krzywda's and Arkademy's Blogconf and #5days5blogposts challenge. I recommend checking him out, and checking what Arkademy offers in terms of courses and sharing knowledge about programming - not only about code per se, but also about just making what you create better in every way.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
