Saturday, August 21, 2010

Dynamically removing parameters from an ObjectDataSource and LinqDataSource within a ReportViewer LocalReport

If you've been using the ReportViewer in your web application, you've probably encountered having to deal with dynamically adding and removing parameters from a datasource to dynamically change your query statement in your report.  This is useful if you provide your users a filter for ad hoc reporting.  You could have radio buttons or drop downs on your report page to allow your users to filter search results.

If you are using Linq in your application, there's a LinqDataSource control that you can use to make calls using your DataContext object.  In the example below, my LinqDataSource object has a Where condition parameter:  StudentStatusID == @StudentStatusID


 <asp:LinqDataSource ID="ldsExamCompleted" runat="server" 
        ContextTypeName="MyDataContext" EntityTypeName="" 
        Select="new (StudentID, FirstName, LastName, ExamDate)" 
        TableName="Students" 
        
    
        Where="StudentStatusID == @StudentStatusID" 
        OrderBy="LastName">
        <WhereParameters>
            <asp:QueryStringParameter Name="StudentStatusID" QueryStringField="status" 
                Type="Int16" />
        </WhereParameters>
    </asp:LinqDataSource>


 For example on the aspx page we have an html dropdown named Status with 3 possible values:  Active (value=1), Inactive (value=2) and Both (value=0).  Each time we change the value on the dropdown, we pass the value as a querystring parameter.  Let's say we choose Both on the dropdown.  Our code behind would look like this.

            if (!IsPostBack)
            {
                ReportViewer1.LocalReport.DataSources.Clear();

                ParameterCollection examParams = ldsExamCompleted.WhereParameters;

                //if user chooses 'Both' on status dropdown
                if (Request.QueryString["status"] == "0"
                {

                    Parameter p = examParams["StudentStatusID"];
                    ldsExamCompleted.WhereParameters.Remove(p);
                }
            }

Here, we removed the where condition parameter "StudentStatus == @StudentStatusID" from our Linq select query and our DataContext object returns all results.  That simple.

So when should you use an ObjectDataSource in your ReportViewer?  An ObjectDataSource is ideal if you use  TableAdapters.  TableAdapters provide communication between your application and the database.  TableAdapters are automatically created when you add a DataSet to your project.  You pass parameters from your ObjectDataSource to your TableAdapter if the Select method on your TableAdapter expects parameters.   Below is a sample of an ObjectDataSource on the aspx page:

   <asp:ObjectDataSource ID="odsExamCompleted" runat="server" 
        OldValuesParameterFormatString="original_{0}" SelectMethod="GetDataByStatusID" 
        
        TypeName="dsStudentTableAdapters.vwExamResultsTableAdapter">
        <SelectParameters>
            <asp:QueryStringParameter Name="StudentStatusID" QueryStringField="status" 
                Type="Int16" />
        </SelectParameters>
    </asp:ObjectDataSource>



Unlike a LinqDataSource where you can remove Where Condition parameters such as "StudentStatusID == @StudentStatusID", an ObjectDataSource can only remove the Select parameter StudentStatusID.  So if you try to remove this parameter from your ObjectDataSource, it will error out since your TableAdapter expects this parameter on its where clause.  You will need to add another Select method to your TableAdapter if you need to have a parameterless query or one with additional parameters.  So on our TableAdapter, I defined 2 Select methods.  One named GetDataByStatusID which expects a @StudentStatusID parameter and one named GetData which doesn't expect any parameter. 


Let's say we want to achieve the same results as our LinqDataSource  example above, this is what we should do on our code behind:
           
               if (!IsPostBack)
            {
                ReportViewer1.LocalReport.DataSources.Clear();

                ParameterCollection examCompletedParams = odsExamCompleted.SelectParameters;

                //if user chooses 'Both' on status dropdown
                if (Request.QueryString["status"] == "0"
                {

                    Parameter p = examCompletedParams["StudentStatusID"];
                    odsExamCompleted.SelectParameters.Remove(p);

                    odsExamCompleted.SelectMethod = "GetData";
                }
            }

Hope this helps anyone implementing ad hoc reporting on their web applications.


Friday, August 20, 2010

How to secure a web folder in IIS 7 by denying IP addresses other than your own

I spent 3 days trying to think of a way to secure a web folder which contained sensitive files. I wanted public users to be able to upload files to that folder but i didn't want them to be able to view it. In other words, Write but no Read. The only way to view the file is within my application which the user needs to be authenticated using Forms Authentication (SqlMembershipProvider). Now there were different approaches on how to secure web folders. The 1st one is using ASP.NET authorization which looks like this on a web.config:

<location path="uploads">
     <system.web>
          <authorization>
               <allow users="myself"/>
               <deny users="*"></deny>
         </authorization>
     </system.web>
</location>

Sadly, this didn't work. Anyone could just type in the full url path to the file and view it without being authenticated.

The 2nd one is through IIS 7 URL Authorization which looks like this on a web.config:

<location path="uploads">
       <system.webServer>
             <security>
                  <authorization>
                          <add accessType="Allow" users="myself" />
                          <remove users="*" roles="" verbs="" />
                  </authorization>
             </security>
       </system.webServer>
</location>

Excitingly, this blocked all requests to the files I wanted to hide. Sadly, even my application wasn't able to access the files. IIS 7 URL Authorization doesn't care about any ASP.NET authenticated user.

The 3rd option was the one that worked for me. Using IIS 7 Url Rewrite, I created a rule denying requests from IP addresses that don't match my server's IP address. Just put a web.config file into the folder you want to secure and put the entry below. Just replace the IP address below with your server's IP.

<system.webServer>
      <rewrite>
            <rules>
                 <rule name="RequestBlockingRule1" patternSyntax="Wildcard"                   stopProcessing="true">
                        <match url="*" />
                                <conditions>
                                        <add input="{REMOTE_ADDR}" pattern="77.11.36.12" negate="true" />
                                </conditions>
                                <action type="CustomResponse" statusCode="403" statusReason="Forbidden: Access is denied." statusDescription="You do not have permission to view this directory or page using the credentials that you supplied." />
                  </rule>
           </rules>
      </rewrite>
</system.webServer>

Hope this helps someone out there.

Monday, July 19, 2010

WebHost4Life too good to be true

After hosting my sites with GoDaddy for years, i finally got fed up. GoDaddy won't allow full trust .NET hosting. I wanted to run Microsoft Reports on my site but all i got was this error:

Security Exception

Description: The application attempted to perform an operation not allowed by the security policy. To grantjavascript:void(0) this application the required permission please contact your system administrator or change the application's trust level in the configuration file.

Exception Details: System.Security.SecurityException: That assembly does not allow partially trusted callers.

I tried searching on the web for hosting companies that allowed full trust .NET and there were 2 that I saw: WebHost4Life and DiscountASP.NET. WebHost4Life was cheaper and had a unlimited storage shared hosting plan. They also had a lot of good reviews about customer service. I wanted to do a test drive on WebHost4Life so I tried signing up for the basic plan which cost $4.95 per month. I went to the Control Panel looking for the MS-SQL admin but then realized that the basic plan didn't include MS-SQL. So I had to upgrade to the next plan which is Advanced which cost $9.95 per month and gives you 5 MS-SQL databases.

The first problem I encountered was not being able to use the Database Publishing Wizard to export my data into WebHost4Life. With GoDaddy this worked like a charm. I called WebHost4Life support asking them if they had a Service Address I could connect to such as (https://mydatabase.webhost4life.com) but I guess they didn't know what I was talking about. They even asked me to try weird addresses like https://g3misa.webhost4life.mysql.com! How weird is that!!! They transferred me to a Senior Support Analyst who even said that connecting remotely to WebHost4Life databases is not allowed. Hello!?? It clearly says on your website that it is strongly suggested to use SQL Management Studio to connect remotely to your database. Anyway, I gave up on that option. So now my only option for exporting my data is running insert scripts on their server. Since WebHost4Life recommends using SQL Management Studio to connect to their databases remotely, this allows you to create and edit database objects directly from your SQL Management Studio client. While trying to do so, I kept getting a credentials error. So I tried creating several SQL accounts and still got the same credentials error. I contacted their Tech Support once again and they said they could reproduce the issue. It took them 1 day to solve this issue.

So after being able to run scripts on my WebHost4Life database, it was time for me to upload my .NET project files. Since they didn't have their own FTP client (which GoDaddy has), I downloaded FileZilla FTP client. I tried using the default ftp login credentials but it wouldn't connect. It kept giving me a Server Error. Even after creating several ftp accounts, the error wouldn't go away. So I had to call WebHost4Life for the 3rd time asking about this error. They said they would fix it asap. It took another day for me to be able to start using FTP.

Now that my files were on the server, I was so excited to see my pages. So after entering the URL, I get a 500-Internal Server Error. So I go to my WebHost4Life Control Panel and clicked on IIS Administration Console. There i noticed that the .NET Runtime is defaulted to .NET 1.1. So I changed it to .NET 3.5. Also i had to create a new folder below my root folder which had to be set as the application folder. They said it would take 2 hours at the most for these changes to take effect. After waiting more than 2 hours, i still got the same Internal Server Error. So I called WebHost4Life for the 4th time asking about this problem. They is what they said:

We are experiencing the issue with our server and we are aware of the issue. Our engineers are working on the issue and it will be resolved as soon as possible. Once the issue is resolved, you will be able to access your website.

Out of curiousity I asked if I was the only one getting this error and they said No it wasn't only me. That suddenly gave me the chills. How can a hosting company provide this kind of service??? Anyway, it's now my 3rd day with WebHost4Life and I haven't seen how my website looks except for the 500-Internal Server Error. I'm giving this another day. If they can't fix it i am moving to DiscountASP.net.

Ok, the Internal Server Error is gone after waiting for a day. The database is working fine. Problem is that whenever i create a new database login, it can't connect to the database at all. That's it, i'm out of here. At this very moment, I am actually trying out DiscountAsp.NET hosting. What took me 4 days to set up in WebHost4Life, took me only an hour on DiscountAsp.NET. What a breeze!!! For all you ASP.NET and MS-SQL Developers, if you need fast, reliable, affordable, great customer service, DiscountAsp.NET is the way to go!!!

Wednesday, April 28, 2010

Song Guru - A Facebook Game Application for Music Listeners

On my previous post, i mentioned about the first Facebook app i created called Song Guru.  The app is here:  http://apps.facebook.com/songguru

Here's the description:

Are you an avid music listener who knows the top songs in the land? Are you able to identify the artist and title when you hear a tune? The rules are simple, choose the correct title and artist of each song that we play for you. If you get all 10 correctly in the least amount of time, then you are a SONG GURU!

Playing the game is easy.  Here are the instructions:

When you hear the music play, find the correct song title on one of the boxes. Depending on the level you choose, there can be 10, 15, 20, 25 or 30 boxes (choices). When you click on the correct box, you earn a point, the box turns green and the next song plays. If you choose an incorrect box, you don't get a point (of course), and the box with the correct title turns red and the next song plays. Try it out now! Choose a Level and click Start to begin playing. Good luck!

Here's a screenshot of the game once it ends:

Tuesday, April 27, 2010

Building my first Facebook Application

So I went through the Facebook documentation on how to build an app. It was very easy and straightforward. There was an example app called Footprints. I downloaded the PHP code along with the Facebook PHP client library and FTP'd it to my host. I thought of using the example code as my initial code and i'd just build on top of it. I had to also set up a MySQL database on my host for the app to run. You just run an SQL script provided in the Footprint sample app.

Configuring the app on facebook was a breeze. You go to: http://www.facebook.com/developers/ and click on Set up New Application.  Facebook gives you an Application key and a secret key to use on your client code.

You just need to specify the Canvas url which is the absolute path to your index.php on your host. For example:

Canvas Callback Url : http://myhost.com/myapp/index.php

Of course you need to supply the Canvas Page Url. This is like searching for a domain name. I wanted to get apps.facebook.com/MusicGuru but it was already taken so I just chose apps.facebook.com/SongGuru

Then i went back to the Footprints PHP code and entered the App key and Secret key on the config.php.

So after setting this up, i was ready to test the Footprints app.

I went to apps.facebook.com/songguru to see what it looked like.

The first problem I ran into was a minor database config error.

Warning: mysql_query(): supplied argument is not a valid MySQL-Link resource in /.../footprints/lib.php on line 11

So, the fix was just to specify 'localhost' as the IP address of your database on the config.php file

// The IP address of your database
$db_ip = 'localhost';

Another error was when I clicked on Step button:

Warning: Missing argument 3 for FacebookRestClient::notifications_send(), called in /.../footprints/lib.php

The fix was to add a 3rd parameter to this API call:

$result = & $facebook->api_client->notifications_send($to, ' stepped on you. ' .'../apps.facebook.com/songguru/.', 'app_to_user');

Another error was this:

Fatal error: Call to undefined method FacebookRestClient::feed_publishActionOfUser() in /.../footprints/lib.php on line 58

Turns out that this API call is obsolete:

$facebook->api_client->feed_publishActionOfUser($feed_title, $feed_body);


So I replaced it with this:

$facebook->api_client->feed_publishUserAction($feed_title, $feed_body);

After that most of it seemed to work. I could see stuff saved to the database.

Now it was time to create the functionality for SongGuru. So i got rid of some example code and retained the important ones for logging in, displaying the name, and publishing the stream. Next thing to do was create the client side stuff. When i configured my App earlier, I had been deciding whether to use an iframe or FBML for my Canvas render method. I chose the FBML of course. The iframe approach was too easy. I wanted to burden myself with Facebook code.

So with FBML, you don't need to put 'html' and 'body' tags. This is already taken care of by the canvas. You can put html tags, css, javascript and FBML (Facebook's tag-based API calls). And so i put all those.

When I tested the app once again I was wondering why my Javascript wasn't working??? If you choose FBML as your render method, most of your javascript functions will not work. You have to use FBJS which is Facebook's own Javascript wrapper functions. For example:

myAnchor.href = 'blogger.com' becomes myAnchor.setHref('.blogger.com')
myButton.value = 'Submit' becomes myButton.setValue('Submit')
myDiv.innerHTML = '' becomes myDiv.setTextValue('')

Setting css classes would have to be like this:

document.getElementById('panel').setStyle('visibility', 'visible');

Facebook canvas already has the clearfix css class defined so you do not have to write your own clearfix rule. Just add class='clearfix' to your tags that need it.

Also getElementsByTagName and getElementsByName do not work. You can only use getElementsById.

You can also make Facebook Javascript API calls inside the canvas. For example:

Facebook.showPermissionDialog('publish_stream,read_stream');

This will display a dialog box asking the user's permission for automatic updates by the app.

To sum it up, it was very easy creating a Facebook app. I love how Facebook created their APIs. Of course you need to think of something interesting to create. My next post will talk about the app I made.

Sunday, April 11, 2010

DZOIC CLIPHOUSE Video Sharing Script REVIEW

Overview

This is a relatively new product in the market. You can hardly find any reviews on it on the web. Their knowledge base is pretty small. They have a members forum with a lot of complaints from customers on how tech support takes too long to (or never) respond.

I have evaluated different video sharing scripts on the market including Clipshare the most popular one. All of them have similar features but only Cliphouse beat the others with their Video Ads plug-in. The Cliphouse admin has the ability to configure different banners (mid-rolls, pre-rolls, etc) to display on a specific video or a category of videos. Other scripts, including Clipshare can only set mid-roll ads for all videos. This was the primary reason why I chose Cliphouse.

After an impressive online demo of Cliphouse, we decided to purchase their product along the following:

1. Script installation option - They do the installation of the script on your server.
2. Branding free option - They remove all links to DZOIC on your site.
3. Load balance plug-in - For better performance on a multi-server setup. I haven't used up my credit for this yet.
4. Server setup option - They configure the modules on your server to make sure everything works properly. I haven't used my credit for this yet. I'm saving it for a rainy day.
5. Video ads plugin - For advertising on the video player. The main reason I chose this product.

Cliphouse has a hosting partner called DHS. We chose Vexxhost hosting instead of DHS for price reasons. DHS hosting was more expensive and had less storage. We chose Shared hosting to see if the product works the cheapest way possible.

Problems Encountered

1. Failed to find flength file

The Cliphouse script installation was almost useless. They just install the script and leave you to do the rest of the configuration. For instance, after script installation, I tried uploading a 2MB video, and I immediately got the popular "Failed to find flength file" problem. I went to their knowledge base and they had the solution for this:

a) First of all make sure that /cgi-bin/ directory and file /cgi-bin/ubr_upload.pl have 755 permissions.
b) Make sure uploader/tmp has write permissions.

So i did both these, and the uploader started working.

2. Progress bar not working

The uploader worked now. The only thing I couldn't see was the progress bar. I didn't find anything on the knowledge base for this so I just dug into the PHP code. The problem was that the div for the progress bar was pointing to a background image that wasn't existing. So I just put a background color on that div and now i could see the progress bar.

3. Videos do not show up or Unfortunately Video May Not Be Converted

This issue was a pain. This problem was intermittent and I couldn't figure out why it was happening for most videos i uploaded. As soon as you upload a video, you get redirected to a page that says the video was uploaded successfully. But then your video is nowhere to be found on the site. Then you notice a message from Admin saying that the video was deleted because the video could not be converted. The solution for this was to specify the correct path for the following: ffmpeg, flvtool2, mencoder, mplayer. So on Cliphouse admin, you just go to Setup -> Paths and enter the correct paths to those encoders. For vexxhost the paths are typically these:

/usr/local/vencode/bin/ffmpeg
/usr/local/vencode/bin/flvtool2
/usr/local/vencode/bin/mencoder
/usr/local/vencode/bin/mplayer

If you are not sure about the paths, ask your hosting provider. If you have access to the console. Type whereis ffmpeg and it will give you the path for it.

4. Progress Bar gets stuck and 500 Internal Server Error

Now this was a major frustration. Sometimes when I upload a video, it would get stuck at a random point. For example, after waiting for an hour the progress bar would get stuck at 99% and throw an Internal Server Error. Sometimes it would get stuck at 15% or 60%. Cliphouse Tech support took 2 weeks to get back to me with no solution to the problem. They told me to change the default uploader, UBER-UPLOADER to Uploadify, a JQuery uploader. I started scratching my head because I have tried Uploadify and i am familar with what it does. I don't think the problem here was the uploader. There were 2 things I suspected, it could either be a problem with the Cliphouse script or a problem with the my Hosting provider, Vexxhost. I contacted Vexxhost and asked them if I could upgrade to VPS hosting. VPS hosting is like having a dedicated server but on a VM (virtual machine). If you're familiar with VMWare or VirtualPC, you'll know what i'm talking about. To my surprise it did solve the problem! Now I could upload videos smoothly without errors.


5. Audio and Video not in sync

I am stuck with this now. The synchronization problem is very obvious and I am still waiting for a reply from DZOIC. Vexxhost says this is not a hosting problem since it involves encoding and it's most probably the script. I am hoping to get a solution to this the soonest. If not, then I am gonna have to look for a different video sharing software.

CONCLUSION

To conclude, DZOIC Cliphouse is a very good product (if you get it to work). It has lots of great features and very easy to use. I looked at the source code and it is very well written. Installation is easy and the admin tool is very powerful. But they need to focus and invest more on customer support. We bought the Cliphouse script a month ago and we haven't gotten it to work properly. This is a very bad experience and can cause their customers to get frustrated and just look for a different product. As for me, I still have credit for the Server Installation. This is my last option. If they don't get this thing to work properly, Goodbye Cliphouse!

UPDATE (Nov 19, 2010)

Tried it on DHS Shared Hosting and i'm getting that #5 error again.  I had the script installed by DZOIC.  Well i think they outsourced the installation  because it was a guy named Frank R. from to Fandar-IT who installed the script.  So looks like DZOIC is really a failure.  I thought DZOIC and DHS were a perfect match.

Saturday, March 20, 2010

sudo: must be setuid root - MAC OSX

As soon as i discovered Snow Leopard had built-in PHP and Apache, i immediately tinkered around with config files through the vi editor which i haven't used in 10 years. Being mostly a .NET developer, it was a pain using the terminal window to set permissions on folders and files. I discovered that you could configure your Finder to display hidden folders such as etc and usr by typing this on the terminal window:

defaults write com.apple.finder AppleShowAllFiles -bool true

Seeing all the hidden folders and files on the Finder window made me so excited that the first thing i did was Add myself to have Read/Write permissions on the etc and usr folders. The next thing i did got me into trouble. I clicked on "Apply to Enclosed Items" which cascaded the change to all files and subfolders under etc and usr.

After doing this, i tried restarting Apache by typing this on the terminal window:

sudo /usr/sbin/apachectl restart

and that's when I started seeing this message:

sudo: must be setuid root

I exited the Terminal Window and re-opened it and now I was even getting this error:

login: PAM Error (line 396): System error
login: Could not determine audit condition

[Process completed]


After googling solutions to this problem, i found the fix which was to delete the file
/usr/bin/login and after that I was able to use Terminal window again.

Now going back to the original problem which was finding a fix for sudo: must be setuid root, I went to Utilities -> Disk Utility and selected my Hard drive, Macintosh HD. I clicked Repair Disk Permissions and everything seems to be working again.

Hope this helped anyone who ran into this problem.

MyPlaylist - Another cool Google Gadget!

Here's another google gadget we created called MyPlaylist. It's very easy to use. All you need to do is enter a MySpace vanity name and you get that user's playlists. You can play each playlist using the MySpace music player. It would be cool to know what other people are listening to especially the artists themselves. Listen to your friends' playlists as well as your own. Enjoy!
By the way, if you want to add this gadget to your iGoogle page, just click on this: Add to iGoogle

Friday, February 5, 2010

MySpace Music Top Songs

If you like the gadget you see below, then click this button to add this gadget to your iGoogle or to embed on your website:

Add to iGoogle



Listen to Top Songs on MySpace Music! Filter by Genre and Territory to see what's hot. Click on the play button to activate the Music Player . Click View More to see Top Charts on Artists Bands Videos Songs and Albums .