Developed my ME, for ME, with only ME in mind.
Well, not really, but it was my initial thought when starting development of my latest project RADLogger. After reviewing many ham radio logging programs, and honestly not liking most of them for various reasons, it became obvious that I should simply write my own amateur radio logging program. After spending several months thinking and experimenting with different data storage engines, I had the honest thought that just maybe others might want to use this.
However, I couldn't let that drive my development and design. Thinking, "how would others like this," just clouded my thinking. Maintaining the "how would I like this," mind-set removes a lot of ambiguity in my development process. Do I want this button? Do I think this import process is cumbersome? Do I think this copy/paste feature will be helpful? Developing a program just for me makes the process easier.
For those interested in the development progress and feature list of RADLogger, simply browse over to www.ruralruins.com/w/blog/ . For now, that is where my development notes will reside. In the future, perhaps, I will have a dedicated page just for my ham radio interests.
73's all
KC7RAD
Rants and Tips from a Crazy Old Telecommuting Programmer.
Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts
Saturday, September 1, 2018
Friday, November 17, 2017
Sell-out? Pragmatist?
So, am I a sell-out or just a pragmatist?
Long ago, nearly ten years before Linux was released, I enjoyed the simple, no-nonsense, high-performance properties of the UNIX/Linux culture. The belief that a tool should only be as complicated as required by the task and no more, truly resonated in my young mind. Being a down-home, poor farm boy, I had very little appreciation for "bells and whistles". And, as such, over the years I have enjoyed Linux.
Unfortunately my inner pragmatist needs to come out of the closet. Why? There are two hobbies that I would like to enjoy more fully: photography & ham radio. Certainly there are great programs that run in Linux for both hobbies. Unfortunately, aside from a few exceptions, I must admit, the better applications run under Windows.
Still on the fence, I evaluated my complete set of needs. Certainly, programs running on Linux could support my basic list of user requirements. There are some ham radio programs out there. There are some great photo utilities like RawTherapee and ImageMagick on Linux. Still walking that fence.
But there is one additional requirement... I want to spend some time honing my C# and .NET skills. Sure there is MONO on Linux; spending an afternoon with MonoDevelop and MONO pushed me in a different direction. There is no way I could hone my C# skills using MONO.
So... I re-evaluated... Sure, Linux has RawTherapee, but Windows has ACDsee, the Canon DPP and a host of other photo management and manipulation programs.
Certainly, there are some great programs under Linux for amateur radio, but I want to get back into PSK31 and maybe SSTV and HSCW. The programs in Windows are far more flexible than those for Linux IMHO. And, honestly, there are no decent, up-to-date logging programs for Linux. Certainly there are some ham radio logging programs for Linux but they don't meet my requirements.
And so... I made a change. Earlier this week I backed up my Linux machine and installed Windows 10.
Honestly, it has issues that I will write about later, but I am not ashamed. Already I have ACDsee Studio running for photo management and DPP & RawTherapee installed for image development and manipulation. OpenOffice runs well and I have Microsoft VisualStudio 2015 installed for programming and honing my C# skills.
No, I am not a sell-out. I am a pragmatist.
Long ago, nearly ten years before Linux was released, I enjoyed the simple, no-nonsense, high-performance properties of the UNIX/Linux culture. The belief that a tool should only be as complicated as required by the task and no more, truly resonated in my young mind. Being a down-home, poor farm boy, I had very little appreciation for "bells and whistles". And, as such, over the years I have enjoyed Linux.
Unfortunately my inner pragmatist needs to come out of the closet. Why? There are two hobbies that I would like to enjoy more fully: photography & ham radio. Certainly there are great programs that run in Linux for both hobbies. Unfortunately, aside from a few exceptions, I must admit, the better applications run under Windows.
Still on the fence, I evaluated my complete set of needs. Certainly, programs running on Linux could support my basic list of user requirements. There are some ham radio programs out there. There are some great photo utilities like RawTherapee and ImageMagick on Linux. Still walking that fence.
But there is one additional requirement... I want to spend some time honing my C# and .NET skills. Sure there is MONO on Linux; spending an afternoon with MonoDevelop and MONO pushed me in a different direction. There is no way I could hone my C# skills using MONO.
So... I re-evaluated... Sure, Linux has RawTherapee, but Windows has ACDsee, the Canon DPP and a host of other photo management and manipulation programs.
Certainly, there are some great programs under Linux for amateur radio, but I want to get back into PSK31 and maybe SSTV and HSCW. The programs in Windows are far more flexible than those for Linux IMHO. And, honestly, there are no decent, up-to-date logging programs for Linux. Certainly there are some ham radio logging programs for Linux but they don't meet my requirements.
And so... I made a change. Earlier this week I backed up my Linux machine and installed Windows 10.
Honestly, it has issues that I will write about later, but I am not ashamed. Already I have ACDsee Studio running for photo management and DPP & RawTherapee installed for image development and manipulation. OpenOffice runs well and I have Microsoft VisualStudio 2015 installed for programming and honing my C# skills.
No, I am not a sell-out. I am a pragmatist.
Sunday, November 6, 2016
Simple Is Still Simple
Yes, contrary to the conventional state of technology and computer programming, simple is still simple. Well, at least it should be.
Quite frequently I read different articles about programming in an attempt to maintain professional relevance. Some are well written articles on good programming techniques. Some are poorly written but the core material is still good. Some are well written pieces about some fluff fad and then there are occasionally the poorly written article about some programming technique or library or concept that has 'bad idea' written all over it.
Quite frequently I read different articles about programming in an attempt to maintain professional relevance. Some are well written articles on good programming techniques. Some are poorly written but the core material is still good. Some are well written pieces about some fluff fad and then there are occasionally the poorly written article about some programming technique or library or concept that has 'bad idea' written all over it.
Thursday, September 22, 2016
Getting a 500 Error When Trying to Access a REST API from C#?
This just might be the solution.
Here's the deal... I need to write a simple C# client to access data from a REST API served up by an Apache Tomcat server. Not a big deal at all... should be pretty simple...
Should be...
For some unknown reason, my attempts generated nothing but '500' errors from the server. Myself and our resident network wizard captured my traffic and we compared the headers of a successful GET using CURL and the non-successful attempt using my simple C# program.
After trying a few things with no success, I noticed the CURL capture showed an 'Accept: */*' header. My C# program did not. So, I added this...
request.Accept = "*/*";
SHAZAM!!! No more 500 errors.
No search results from Google helped. None mentioned this as being a possibility. But, heck... it worked.
By the way, this Apache server is what I like to call LegalWalled. Yes, it's our server but if we touch it, or even log onto it using SSH without the guidance and approval of the vendor's support group, we could violate our support contract... so opportunity to dig into why that specific error was generated.
Here's the deal... I need to write a simple C# client to access data from a REST API served up by an Apache Tomcat server. Not a big deal at all... should be pretty simple...
Should be...
For some unknown reason, my attempts generated nothing but '500' errors from the server. Myself and our resident network wizard captured my traffic and we compared the headers of a successful GET using CURL and the non-successful attempt using my simple C# program.
After trying a few things with no success, I noticed the CURL capture showed an 'Accept: */*' header. My C# program did not. So, I added this...
request.Accept = "*/*";
SHAZAM!!! No more 500 errors.
No search results from Google helped. None mentioned this as being a possibility. But, heck... it worked.
By the way, this Apache server is what I like to call LegalWalled. Yes, it's our server but if we touch it, or even log onto it using SSH without the guidance and approval of the vendor's support group, we could violate our support contract... so opportunity to dig into why that specific error was generated.
Tuesday, March 29, 2016
OMG .NET, You Are Crazy!!!
OK, so I am doing something simple... adding a ControlParameter to a SQLDataSource. I just want to add it as an optional filter. The ControlParameter points to a TextBox. Like this...
<asp:ControlParameter ControlID="txtFiltCC" Name="TCity" PropertyName="Text" Type="String" DefaultValue=""/>
Not only does the result return nothing, according to the Microsoft SQL Server Profiler, the query is never even sent to the server!!!
What the HELL!?!?!?!?
I change the SelectCommand to not use the @TCity paramater and still... no query sent. The GridView bound to the SQLDataSource reports that no records were retrieved. Hmmm... makes sense since according to SQL Server Profiler, no query was sent.
Then I find the ConvertEmptyStringToNull property on the ControlParameter. It's default is 'True'. Hell, I don't want it to be null, so I change it to False. Friggin SHAZAM! The SQL query is sent and I get a result set. Why the HELL would the ConvertEmptyStringToNull cause a query to not be sent, especially if the parameter isn't even used in the query???? This works fine...
<asp:ControlParameter ControlID="txtFiltCC" Name="TCity" PropertyName="Text" Type="String" ConvertEmptyStringToNull="False" DefaultValue=""/>
Really, Microsoft... This is a crazy little piece in ASP.NET
So... For anyone scratching their head about a GridView not being populated from a SQLDataSource that is using a ControlParameter pointing to a TextBox, this just may be the solution.
<asp:ControlParameter ControlID="txtFiltCC" Name="TCity" PropertyName="Text" Type="String" DefaultValue=""/>
Not only does the result return nothing, according to the Microsoft SQL Server Profiler, the query is never even sent to the server!!!
What the HELL!?!?!?!?
I change the SelectCommand to not use the @TCity paramater and still... no query sent. The GridView bound to the SQLDataSource reports that no records were retrieved. Hmmm... makes sense since according to SQL Server Profiler, no query was sent.
Then I find the ConvertEmptyStringToNull property on the ControlParameter. It's default is 'True'. Hell, I don't want it to be null, so I change it to False. Friggin SHAZAM! The SQL query is sent and I get a result set. Why the HELL would the ConvertEmptyStringToNull cause a query to not be sent, especially if the parameter isn't even used in the query???? This works fine...
<asp:ControlParameter ControlID="txtFiltCC" Name="TCity" PropertyName="Text" Type="String" ConvertEmptyStringToNull="False" DefaultValue=""/>
Really, Microsoft... This is a crazy little piece in ASP.NET
So... For anyone scratching their head about a GridView not being populated from a SQLDataSource that is using a ControlParameter pointing to a TextBox, this just may be the solution.
Friday, November 6, 2015
C# Background Workers Using Shared Memory
It doesn't happen often in my particular coding shop, but once in a rare while the requirement for different threads in a program to use a shared memory variable rears it's head. It really isn't difficult to handle this requirement in C#; actually, it is surprisingly easy if you are careful to avoid deadlock situations,
The key to this solution is a simple static class:
using System;
using System.Collections.Generic;
using System.Text;
namespace ThreadCom
{
static class StaticShare
{
public static object MsgLock = new object(); // Functions as a lock when accessing Messages.
public static string Messages = ""; // This is what is shared and used in all threads of this sample program.
}
}
Basically, this snippet of C# code creates a static class with two public properties: MsgLock and Messages. MsgLock is used to control access to Messages; a string that contains the data shared among the different threads. Remember, performance is important; keep the shared static variable terse and small.
Here is how a thread (specifically a BackgroundWorker) might use the StaticShare class to lock, access and change the shared data without causing noticeable contention or throwing exceptions:
lock (StaticShare.MsgLock)
{
ReportProgress(0, "From " + BWName + " -> " + StaticShare.Messages);
StaticShare.Messages = BWName + " current time: " + DateTime.Now.ToString();
}
The first line locks MsgLock, or causes the thread to wait until another thread's lock is released. The ReportProgress() line is a method belonging to a BackgroundWorker, that line, in this case is accessing our shared variable Messages. The last line in the Lock() block assigns something to the shared variable.
One big caveat here... Make the code within the lock() block short, concise, to the point and fast. If the code there is time-consuming or performs poorly, the lock() could cause other threads to be blocked.
Remember... thread blocking is not cool!
You can download the entire c# project from my Google Drive here. Standard code disclaimer: This code is for education, information and perhaps a few laughs. It may not be perfect but does demonstrate a valid implementation of using shared storage with a multi-threaded C# application.
-whew-
The key to this solution is a simple static class:
using System;
using System.Collections.Generic;
using System.Text;
namespace ThreadCom
{
static class StaticShare
{
public static object MsgLock = new object(); // Functions as a lock when accessing Messages.
public static string Messages = ""; // This is what is shared and used in all threads of this sample program.
}
}
Basically, this snippet of C# code creates a static class with two public properties: MsgLock and Messages. MsgLock is used to control access to Messages; a string that contains the data shared among the different threads. Remember, performance is important; keep the shared static variable terse and small.
Here is how a thread (specifically a BackgroundWorker) might use the StaticShare class to lock, access and change the shared data without causing noticeable contention or throwing exceptions:
lock (StaticShare.MsgLock)
{
ReportProgress(0, "From " + BWName + " -> " + StaticShare.Messages);
StaticShare.Messages = BWName + " current time: " + DateTime.Now.ToString();
}
One big caveat here... Make the code within the lock() block short, concise, to the point and fast. If the code there is time-consuming or performs poorly, the lock() could cause other threads to be blocked.
Remember... thread blocking is not cool!
You can download the entire c# project from my Google Drive here. Standard code disclaimer: This code is for education, information and perhaps a few laughs. It may not be perfect but does demonstrate a valid implementation of using shared storage with a multi-threaded C# application.
-whew-
Monday, July 13, 2015
C# Battle - Dynamic Array -versus- Generic Collection
In a previous post I insinuated that using a dynamic array in C#, rather than a dynamic structure might show a certain lack of basic programming skills. Well, after getting my daughter off to work early Saturday morning, a storm rolled in, throwing out my plans to perform a little yard maintenance. So... what to do? How about a little computer play while drinking my morning coffee.
After all, drinking coffee while practicing my guitar has far too many times caused scares due to the possibility of spilled coffee!
So, I set out to prove that Dynamic Arrays are worse performers than Collections in C#. Well... For my tests, my presumptions were proven incorrect. My little test showed that when loading image bitmaps from PNG files into a Dynamic Array, there is only a marginal difference loading into a C# Collection.
Machine Baseline...
CPU: Intel Core i3-3240 @ 3.4 GHz
RAM: 8GB
Windows Version: 7 Ultimate 64 bit.
Hard Drive: ADATA SP920 512MB SSD drive
Number of images to load: 9727
Image size: All are 640 x 480
Read on for the code and specific results...
After all, drinking coffee while practicing my guitar has far too many times caused scares due to the possibility of spilled coffee!
So, I set out to prove that Dynamic Arrays are worse performers than Collections in C#. Well... For my tests, my presumptions were proven incorrect. My little test showed that when loading image bitmaps from PNG files into a Dynamic Array, there is only a marginal difference loading into a C# Collection.
Machine Baseline...
CPU: Intel Core i3-3240 @ 3.4 GHz
RAM: 8GB
Windows Version: 7 Ultimate 64 bit.
Hard Drive: ADATA SP920 512MB SSD drive
Number of images to load: 9727
Image size: All are 640 x 480
Read on for the code and specific results...
Saturday, July 11, 2015
Basic Skills, Please People!
Please!!!
Programmers really should know the basics of a language and platform before coding something that is used in a production environment. Knowing the cool tricks of a language is nice but not knowing how the basics work is just irritating.
Take for instance a little optimization I just finished... A SQL query was returning about 800,000 rows where about 799,700 were duplicates. Adding a distinct to the SQL made the page load about 80% faster. Why did the programmer not use that distinct keyword??? Maybe because they didn't know the basics. Maybe because the programmer was sloppy. Maybe the programmer didn't completely understand what was requested. Don't know.
Then, while looking at the rest of the code I saw several string arrays defined; arrays that, after populated, contained hundreds of items. To build these arrays, Array.Resize was used to add items. Now THAT just might be inefficient. Array.Resize copies the entire array and adds another element. The programmer probably should have used a List<> or some other dynamic structure.
Hmmm... now I am curious...
Programmers really should know the basics of a language and platform before coding something that is used in a production environment. Knowing the cool tricks of a language is nice but not knowing how the basics work is just irritating.
Take for instance a little optimization I just finished... A SQL query was returning about 800,000 rows where about 799,700 were duplicates. Adding a distinct to the SQL made the page load about 80% faster. Why did the programmer not use that distinct keyword??? Maybe because they didn't know the basics. Maybe because the programmer was sloppy. Maybe the programmer didn't completely understand what was requested. Don't know.
Then, while looking at the rest of the code I saw several string arrays defined; arrays that, after populated, contained hundreds of items. To build these arrays, Array.Resize was used to add items. Now THAT just might be inefficient. Array.Resize copies the entire array and adds another element. The programmer probably should have used a List<> or some other dynamic structure.
Hmmm... now I am curious...
Monday, November 10, 2014
C# Programming Tip - ViewState
A C# page's ViewState is a real cool place to put state information and variables you want to stick around for the lifetime of a web page. Actually, most ASP page components save their state information in the ViewState.
Saving stuff in the ViewState is easy. Here is an example:
Accessing it is easy as well:
You can also do cool things like put more complex items in the ViewState like:
So long as the object is seralizable (more on that later), you can save it in the ViewState. There is a big drawback... space and bandwidth. A page's ViewState is stored in the page! So, each time the page loads, is posted or there is a postback, the entire ViewState is sent over the network. If you want to maximize the efficiency of your page, minimize your ViewState usage. The size of a ViewState can grow quickly if you have a large and/or complex page.
Also... ViewStates are NOT secure. With enough smarts a person can decode them, so don't put anything in the ViewState that you want to keep secure.
For those curious, here is what a simple ViewState looks like in a simple page:
Saving stuff in the ViewState is easy. Here is an example:
ViewState["mode"] = "A"
Accessing it is easy as well:
if (ViewState["mode"].ToString() == "A")
{...}
You can also do cool things like put more complex items in the ViewState like:
SomeComplexClass ComplexObject = new SomeComplexClass();
...
ViewState["ComplexObjectVS"] = ComplexObject;
...
SomeComplexClass ComplexObjectCopy = (SomeComplexClass)ViewState["ComplexObjectVS"];
So long as the object is seralizable (more on that later), you can save it in the ViewState. There is a big drawback... space and bandwidth. A page's ViewState is stored in the page! So, each time the page loads, is posted or there is a postback, the entire ViewState is sent over the network. If you want to maximize the efficiency of your page, minimize your ViewState usage. The size of a ViewState can grow quickly if you have a large and/or complex page.
Also... ViewStates are NOT secure. With enough smarts a person can decode them, so don't put anything in the ViewState that you want to keep secure.
For those curious, here is what a simple ViewState looks like in a simple page:
<input id="__VIEWSTATE" name="__VIEWSTATE" type="hidden" value="/wEPDwUJNzkzMjk1ODg4D2QWAmYPZBYCAgEPZBYCAgsPDxYCHgRUZXh0BQgxLjAoZGV2KWRkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYBBSZjdGwwMCRNYWluQ29udGVudCRMb2dpblVzZXIkUmVtZW1iZXJNZbVBilGyAMpTuiSmFozdPPwfgNyhxhHXWwhU4O2NRdBd" />
Subscribe to:
Posts (Atom)