Q:

Why can't we directly reference a memory address using the esp register?

The following is an x86 assembly program meant to be assembled by NASM under 64-bit CentOS over a remote terminal which works absolutely fine when used along with a C program. 
section .data
section .text
        global  strlen

strlen:
        push    ebp
        mov     ebp, esp                ; obtain the address of the
        mov     eax, DWORD [ebp+8]      ; address of string to eax

        xor     ecx, ecx                ; initialize counter to zero

count_loop:
        mov     bl, [eax]               ; obtain the address of the 1st character
        cmp     bl, 0                   ; check the null value
        je      length_exit             ; exit if the null-character is reached
        inc     ecx                     ; increment counter
        inc     eax                     ; increment the address
        jmp     count_loop              ; start the loop again

length_exit:
        mov     eax, ecx                ; return ecx
        pop     ebp                     ;
        ret

First of all, is it a 32-bit or 64-bit program? If it is a 32-bit program why doesn't it have underscore character (_) in the name of the function?
I know that the following code-section is creating a stack-frame:
push    ebp
mov     ebp, esp                ; obtain the address of the
mov     eax, DWORD [ebp+8]      ; address of string to eax

but, why do we need to save ebp? Why can't we just write the following? :
 move eax, DWORD [esp+8]

And, why do we need the type-casting here?
I also need a memory layout of this program to understand the stack mechanism. I have found many pictures in the Internet, but I am not sure which one would be the appropriate one to represent this program. 

A:

If it is a 32-bit program why doesn't it have underscore character (_) in the name of the function?

Because it's not Windows.
Linux/ELF systems don't use a leading _ in any mode, regardless of CPU architecture.

Why can't we just write the following?:  move eax, DWORD [esp+8]

You can.  (If you spell mov correctly).  In fact, compilers default to using -fomit-frame-pointer when optimization is enabled, so they only use EBP as a frame pointer in functions with C99 variable-length arrays, or alloca.
32 and 64-bit mode allow ESP to be a base address for addressing modes, unlike in 16-bit mode where [sp+2] was not encodeable.
But remember that if you haven't pushed ebp, ESP is still pointing at the return address, so the first arg will be at [esp+4].

And, why do we need the type-casting here?

You don't. The register operand implies the operand-size.
(And it's not truly type-casting, just operand-size specifier.  It wouldn't do float-int conversion for you; you'd have to use cvtss2si eax, [esp+4] for that.)
You only need an operand-size specifier for mem,immediate instructions like cmp dword [esp+4], 0, which would be ambiguous between byte/word/dword operand-size.  Or for instructions like movzx eax, byte [esp+4] where the register operand doesn't imply a size for the memory operand.

